Add new BitMarkdownViewer component (#12503)#12506
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe PR replaces the JS/Jint markdown viewer path with a native C# parser, renderer, component, demo, and tests. It adds a pipeline and extension model for Markdown features such as tables, strikethrough, task lists, autolinks, emoji, and automatic heading IDs. ChangesNative C# Markdown Viewer replacement
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cs (1)
30-47: ⚡ Quick winHarden immutability for internal lookup collections.
Line 44–47 expose mutable backing collections through
internalproperties while the class documentation states the pipeline is immutable/thread-safe. Wrapping these maps/lists in read-only containers (and avoiding mutable set exposure) prevents accidental internal mutation.Proposed refactor
+using System.Collections.ObjectModel; ... - InlineParsersByChar = byChar.ToDictionary(kv => kv.Key, kv => (IReadOnlyList<InlineParser>)kv.Value); + InlineParsersByChar = new ReadOnlyDictionary<char, IReadOnlyList<InlineParser>>( + byChar.ToDictionary(kv => kv.Key, kv => (IReadOnlyList<InlineParser>)kv.Value.AsReadOnly())); ... - DelimiterByChar = delimByChar; - DelimiterChars = new HashSet<char>(delimByChar.Keys); + DelimiterByChar = new ReadOnlyDictionary<char, DelimiterProcessor>(delimByChar); + DelimiterChars = delimByChar.Keys.ToHashSet(); ... - internal HashSet<char> DelimiterChars { get; } + internal IReadOnlySet<char> DelimiterChars { get; }🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cs` around lines 30 - 47, The DelimiterChars property on line 36 exposes a mutable HashSet<char> directly, which violates the immutability and thread-safety contract of the BitMarkdownPipeline class. Wrap the DelimiterChars property by changing its return type from HashSet<char> to IReadOnlySet<char> or IReadOnlyCollection<char>, and ensure the internal backing field stores the HashSet while the property returns it wrapped in a read-only view to prevent accidental mutation through the exposed property.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/EmojiExtension.cs`:
- Around line 16-39: The static Emoji dictionary field is mutable and publicly
accessible, but it is also read without synchronization in the Process method
during the Shortcode().Replace operation. This creates a race condition if
callers modify the dictionary at runtime while parsing occurs. Replace the
mutable Dictionary<string, string> field with a thread-safe collection such as
ConcurrentDictionary, or alternatively make it immutable and use a lock when
modifications are needed. Ensure that the TryGetValue call in the Process
method's lambda expression reads from this thread-safe collection safely.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cs`:
- Around line 21-22: The regex pattern in the TaskMarker method currently uses
\s+ which requires at least one whitespace character after the closing bracket,
causing it to reject valid task-list items like "- [ ]" with no trailing text.
Change the quantifier from \s+ to \s* in the TaskMarker regex pattern to make
the whitespace optional while keeping the rest of the pattern intact.
Additionally, check the code around lines 33-37 (mentioned in the comment) for
similar regex patterns that may have the same issue and apply the same fix if
needed.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cs`:
- Around line 13-36: The VisitChildLists and Descendants methods both use
unbounded recursion to traverse the AST tree, which can cause stack overflow
with deeply nested inputs. Refactor both methods to use iterative traversal with
an explicit stack or queue data structure instead of recursive calls. For
VisitChildLists, maintain a queue of nodes to process iteratively, invoking the
action on each node's child lists while pushing child nodes onto the queue for
processing rather than recursing. For Descendants, similarly use a queue to
iteratively yield all descendant nodes without making recursive calls to
Descendants. Both methods should maintain the same traversal semantics and
result order while safely handling arbitrary nesting depths.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BlockProcessor.cs`:
- Around line 66-76: The GetIndent and StripIndent methods are incorrectly
handling tab characters by treating each tab as a fixed increment of 4 columns,
when they should advance to the next tab stop position. In the GetIndent method,
replace the logic that adds 4 when encountering a tab character with logic that
advances the indent variable to the next multiple of 4 (i.e., next tab stop).
Apply the same tab-stop calculation fix to the StripIndent method (lines 78-88).
This ensures that mixed whitespace prefixes are parsed correctly for
indent-sensitive markdown blocks.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreBlockParsers.cs`:
- Around line 148-155: The IsQuote method on line 148 uses TrimStart(' ') which
removes all leading spaces before checking for the blockquote marker, causing
lines with 4 or more leading spaces to be incorrectly identified as blockquotes.
According to Markdown specifications, blockquote markers should only be
recognized when preceded by up to 3 leading spaces. Modify the IsQuote method to
check that the line has at most 3 leading spaces before the '>' character,
rejecting lines with 4 or more leading spaces so that indented code blocks are
properly classified before blockquotes are parsed.
- Around line 195-197: The CanInterruptParagraph method in the CoreBlockParsers
class is allowing any ordered list marker to interrupt a paragraph, but it
should only allow ordered lists starting with "1" to interrupt. Modify the check
on line 197 where BlockGrammar.Ordered().IsMatch is called to add an additional
validation that ensures the ordered marker is specifically for the number "1"
before allowing the paragraph interruption. The bullet list check on line 196
should remain unchanged.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreInlineParsers.cs`:
- Around line 95-111: The AutolinkInlineParser is creating links without
sanitizing URLs through the UrlSanitizer, creating a security vulnerability
where dangerous URLs like javascript:alert(1) bypass validation. Modify all
three Emit calls in this method to sanitize the URL parameter before passing it
to Emit. Specifically, when Emit is called with the URL (either inner for
scheme-based URLs on line 102, "mailto:" + inner for email addresses on line
109, and other cases in lines 116-122), wrap the URL parameter with UrlSanitizer
to ensure all autolinks are sanitized the same way as regular markdown links
are.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cs`:
- Around line 81-89: The IsExternal method is being called with link.Url without
verifying that the URL is not null or empty first, which can cause a runtime
exception when rendering links with missing or invalid URLs. Move the entire
block containing the IsExternal call (the conditional starting with
IsExternal(link.Url) that sets target and rel attributes) inside or after a
null/empty check for link.Url, similar to the existing check on line 81, or add
a guard condition that ensures link.Url is not null/empty before calling
IsExternal. Apply the same fix to the other occurrence mentioned at lines
146-148.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/MarkdownRenderer.cs`:
- Around line 41-51: The WriteNode method in MarkdownRenderer silently exits
without rendering when no renderer matches a node, causing unrendered content to
be lost without any indication of the problem. After the for loop that iterates
through _renderers completes, add error handling to detect when no renderer
accepted the node. Throw an exception or log an error message indicating which
node type could not be rendered, so developers are aware when a renderer is
missing for a particular node type introduced by an extension.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor`:
- Line 48: The textarea element with class "mdv-editor" that binds to
playgroundMarkdown lacks an accessible name for screen readers. Add an
aria-label attribute to the textarea element with a descriptive label (such as
"Markdown editor" or similar) that clearly identifies the purpose of the
textarea to assistive technology users. Alternatively, you could associate the
textarea with a visible or hidden label element using a for attribute if a label
element is already present in the component structure.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cs`:
- Around line 30-47: The DelimiterChars property on line 36 exposes a mutable
HashSet<char> directly, which violates the immutability and thread-safety
contract of the BitMarkdownPipeline class. Wrap the DelimiterChars property by
changing its return type from HashSet<char> to IReadOnlySet<char> or
IReadOnlyCollection<char>, and ensure the internal backing field stores the
HashSet while the property returns it wrapped in a read-only view to prevent
accidental mutation through the exposed property.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9e12abe4-20c9-4a8a-883b-898c75587691
📒 Files selected for processing (41)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/Bundles.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/EmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/StrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/Abstractions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreBlockParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreInlineParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/DelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/MarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoLinkExtension.cs`:
- Around line 13-17: The GeneratedRegex pattern in the AutoLinkExtension class
is missing a start-boundary guard that prevents matching autolinks in the middle
of larger tokens (e.g., foohttps://x.y). Add a word boundary assertion at the
beginning of the regex pattern before the first alternation group to ensure
URLs, www links, and email addresses are only matched when they start at word
boundaries or appropriate positions, not when they appear as substrings within
other tokens.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cs`:
- Around line 93-108: The SplitRow method currently treats every non-escaped
pipe character as a cell separator without considering whether it appears inside
backtick code spans. Add tracking logic to monitor when the parser enters and
exits backtick blocks by checking for backtick characters in the iteration loop
within SplitRow. Only treat a pipe character as a cell separator if it is both
non-escaped (not preceded by backslash) AND not currently inside a backtick code
span. This will allow valid markdown like ``| `a|b` | c |`` to be parsed
correctly with the pipe inside backticks not being treated as a separator.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cs`:
- Around line 72-88: The SplitLines method only recognizes `\n` as a line
boundary in its loop condition, which causes lines separated by standalone `\r`
characters (classic Mac line endings) to be treated as part of the same line.
Modify the loop in SplitLines to check for both `\r` and `\n` characters as line
boundaries, ensuring that `\r\n` sequences are treated as a single line boundary
(not two separate ones) by checking if a `\r` is followed by a `\n` and skipping
the next character appropriately, and verify that the final line handling at the
end also strips any trailing `\r` characters that might remain.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipelineBuilder.cs`:
- Around line 57-64: In the Use method, the extension is added to the
_extensions list before calling extension.Setup(this), which means if Setup
throws an exception, the extension remains registered and prevents retries.
Reorder the operations so that extension.Setup(this) is called first, and only
if it completes successfully should the extension be added to the _extensions
collection using _extensions.Add(extension).
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cs`:
- Around line 96-99: In the ImageNode case within CoreRenderer.cs, the src
attribute is unconditionally emitted via b.AddAttribute even when img.Url is
empty after sanitization, causing empty src attributes to render. Modify the
code to only call b.AddAttribute for "src" with img.Url when img.Url is not
empty or null, mirroring the pattern used in the link branch to avoid rendering
empty src attributes.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cs`:
- Around line 204-222: The example3RazorCode string contains a textarea element
that is missing an aria-label attribute, which creates an inconsistency with the
actual live demo implementation. Locate the textarea element with class
mdv-editor in the example3RazorCode string and add an appropriate aria-label
attribute to ensure the copied code snippet includes the same accessibility
features as the live demo component.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 90781769-51f1-4d70-91f4-6eb2121b03ef
📒 Files selected for processing (41)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/Bundles.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/EmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/StrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/Abstractions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreBlockParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreInlineParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/DelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/MarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs (1)
42-43: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueConsider stripping additional control characters from scheme.
The scheme normalization removes
\tand\n, but other control characters (e.g.,\r, form feed, or null bytes) could potentially be used for obfuscation in crafted inputs. While browsers also normalize schemes, adding\rwould be a low-cost improvement for defense-in-depth.- string scheme = trimmed[..(colon + 1)].Replace("\t", "").Replace("\n", "").ToLowerInvariant(); + string scheme = trimmed[..(colon + 1)].Replace("\t", "").Replace("\n", "").Replace("\r", "").ToLowerInvariant();🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs` around lines 42 - 43, The scheme normalization in the UrlSanitizer class currently only strips `\t` and `\n` characters, but should also remove other control characters for defense-in-depth. In the scheme variable assignment, add additional Replace calls to remove `\r` (carriage return) and consider other common control characters like form feed or null bytes that could be used for obfuscation in crafted inputs, following the same pattern as the existing `\t` and `\n` removals.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cs`:
- Around line 57-60: The ChildLists property override is returning the nested
children of each ListItemNode (via Items.Select(i => i.Children)) instead of
exposing the list items themselves, which violates the traversal contract and
prevents generic processors from visiting ListItemNode objects. Modify the
ChildLists property to return the Items collection itself as a single enumerable
list instead of selecting each item's children, so that generic traversals can
properly inspect and process the ListItemNode objects directly.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs`:
- Around line 42-43: The scheme normalization in the UrlSanitizer class
currently only strips `\t` and `\n` characters, but should also remove other
control characters for defense-in-depth. In the scheme variable assignment, add
additional Replace calls to remove `\r` (carriage return) and consider other
common control characters like form feed or null bytes that could be used for
obfuscation in crafted inputs, following the same pattern as the existing `\t`
and `\n` removals.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 3688caed-3883-47b2-aa13-15746a2b3410
📒 Files selected for processing (41)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/Bundles.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/EmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/StrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/Abstractions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreBlockParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreInlineParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/DelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/MarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs (1)
71-72: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winHarden the unsafe-link test by asserting the rendered
hrefbehavior directly.Line 71 only checks a lowercase substring in HTML, which is brittle. Assert the link renders without an unsafe
href(or with emptyhref) so sanitizer regressions are caught more reliably.Suggested test assertion update
- Assert.DoesNotContain("javascript:", root.InnerHtml); + var link = root.QuerySelector("a"); + Assert.IsNotNull(link); + Assert.IsFalse(link.HasAttribute("href"));🤖 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/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs` around lines 71 - 72, The current test assertion at line 71 only checks if the substring "javascript:" is absent from the HTML content, which is brittle and doesn't directly validate the sanitizer's behavior. Replace the Assert.DoesNotContain check with a more robust assertion that directly accesses and validates the rendered link's href attribute (the actual `href` property of the element) to ensure it is either empty or does not contain any unsafe protocols like javascript:. This will make the test more reliable and catch sanitizer regressions by testing the actual rendered behavior rather than a substring presence check.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cs`:
- Around line 24-31: The current implementation in the traversal loop calls
action for all child lists before descending into any of their children, which
violates depth-first order when a node has multiple ChildLists. To preserve
depth-first visitation semantics, restructure the loop so that for each list in
current.ChildLists, the action is called immediately before that list's children
are collected and pushed to the stack, rather than calling action on all lists
upfront before any children are processed. This ensures each list and its
descendants are fully processed before moving to the next sibling list.
---
Nitpick comments:
In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs`:
- Around line 71-72: The current test assertion at line 71 only checks if the
substring "javascript:" is absent from the HTML content, which is brittle and
doesn't directly validate the sanitizer's behavior. Replace the
Assert.DoesNotContain check with a more robust assertion that directly accesses
and validates the rendered link's href attribute (the actual `href` property of
the element) to ensure it is either empty or does not contain any unsafe
protocols like javascript:. This will make the test more reliable and catch
sanitizer regressions by testing the actual rendered behavior rather than a
substring presence check.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 88cebd48-7668-4eb3-89a7-80571e987883
📒 Files selected for processing (41)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/Bundles.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/EmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/StrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/Abstractions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreBlockParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreInlineParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/DelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/MarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cs (1)
24-31:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftPreserve depth-first list visitation order in
VisitChildLists.Lines 24-28 call
actionfor every child list before descending into any children, which changes the documented depth-first behavior when a node has multipleChildListsand can reorder AST rewrites. The action should be called on each list immediately before descending into that list's children, rather than processing all lists upfront.Recommended fix (preserves per-list DFS semantics)
public static void VisitChildLists(MarkdownNode node, Action<IList<MarkdownNode>> action) { - // Iterative depth-first traversal to avoid stack overflow on deeply nested input. - var stack = new Stack<MarkdownNode>(); - stack.Push(node); - while (stack.Count > 0) - { - var current = stack.Pop(); - // Collect children after invoking the action, since the action may - // replace entries in the list (e.g. splitting a text node). - var children = new List<MarkdownNode>(); - foreach (var list in current.ChildLists) - { - action(list); - children.AddRange(list); - } - // Push in reverse so children are processed in document order. - for (int i = children.Count - 1; i >= 0; i--) - stack.Push(children[i]); - } + var stack = new Stack<(MarkdownNode Node, int ListIndex)>(); + stack.Push((node, 0)); + + while (stack.Count > 0) + { + var (current, listIndex) = stack.Pop(); + if (listIndex >= current.ChildLists.Count) + continue; + + // Resume this node's next list after processing current list subtree. + stack.Push((current, listIndex + 1)); + + var list = current.ChildLists[listIndex]; + action(list); + + // Snapshot because action may replace list entries. + var snapshot = list.ToArray(); + for (int i = snapshot.Length - 1; i >= 0; i--) + stack.Push((snapshot[i], 0)); + } }🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cs` around lines 24 - 31, The current implementation in the VisitChildLists method calls action on all child lists upfront before descending into any children, which violates depth-first traversal semantics when a node has multiple ChildLists. Reorganize the loop so that for each list in current.ChildLists, the action is called on that specific list immediately before adding its children to be processed, rather than iterating through all lists to call action first and then processing all accumulated children. This preserves true depth-first order where each list and its descendants are fully processed before moving to the next sibling list.
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs (1)
13-15: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueConsider allowing
data:URIs for images.The
data:URI scheme is commonly used for embedding base64-encoded images directly in Markdown. Without it, inline images likewill be blocked. If this is intentional for security reasons (e.g., to prevent large payloads or exfiltration vectors), the current behavior is fine. Otherwise, you may want to add"data:"toAllowedImageSchemes.🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs` around lines 13 - 15, The AllowedImageSchemes array in UrlSanitizer.cs currently only permits http: and https: schemes, which blocks data URIs used for embedding base64-encoded images in Markdown. If not already intentional for security purposes, add "data:" to the AllowedImageSchemes array to allow inline images specified with data URIs like data:image/png;base64,...
🤖 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.
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cs`:
- Around line 24-31: The current implementation in the VisitChildLists method
calls action on all child lists upfront before descending into any children,
which violates depth-first traversal semantics when a node has multiple
ChildLists. Reorganize the loop so that for each list in current.ChildLists, the
action is called on that specific list immediately before adding its children to
be processed, rather than iterating through all lists to call action first and
then processing all accumulated children. This preserves true depth-first order
where each list and its descendants are fully processed before moving to the
next sibling list.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs`:
- Around line 13-15: The AllowedImageSchemes array in UrlSanitizer.cs currently
only permits http: and https: schemes, which blocks data URIs used for embedding
base64-encoded images in Markdown. If not already intentional for security
purposes, add "data:" to the AllowedImageSchemes array to allow inline images
specified with data URIs like data:image/png;base64,...
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 98d4af75-47b7-4348-9862-6fabcb7074d2
📒 Files selected for processing (41)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/Bundles.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/EmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/StrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/Abstractions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreBlockParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreInlineParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/DelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/MarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cs (1)
59-60:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftExpose
ListNode.Itemsas an owned child list, not a copied snapshot.
ChildListscurrently allocates a newList<MarkdownNode>viaToList(). That list is detached, so generic AST rewrites on that collection never updateListNode.Items.Suggested direction
public sealed class ListNode : MarkdownNode { - public List<ListItemNode> Items { get; } = new(); + public List<MarkdownNode> Items { get; } = new(); - public override IEnumerable<IList<MarkdownNode>> ChildLists - => new[] { (IList<MarkdownNode>)Items.Cast<MarkdownNode>().ToList() }; + public override IList<MarkdownNode> ChildNodes => Items; }(Then adjust list consumers, e.g. renderer/parser call sites, to cast/validate
ListItemNodewhere needed.)🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cs` around lines 59 - 60, The ChildLists property in ListNode currently creates a detached snapshot of Items using ToList(), which means AST rewrites on that collection don't update the original ListNode.Items. Remove the ToList() call and instead return the actual Items collection directly (wrapped in an array for the IEnumerable interface), ensuring it remains connected to the source. Then update all list consumers and call sites (renderer, parser, etc.) to properly cast and validate ListItemNode items as needed when working with this collection.src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cs (1)
21-22:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winConstrain task marker matching to avoid
[x]foofalse positives.Line 21 currently accepts no-space content after
], so[x]foois rewritten as a task item. Match either an empty marker or whitespace+content only.Proposed regex/assignment adjustment
- [GeneratedRegex(@"^\[([ xX])\]\s*(.*)$")] + [GeneratedRegex(@"^\[([ xX])\](?:\s+(.*))?$")] private static partial Regex TaskMarker(); @@ - text.Text = m.Groups[2].Value; + text.Text = m.Groups[2].Success ? m.Groups[2].Value : string.Empty; para.Inlines.Insert(0, new TaskCheckboxNode { Checked = m.Groups[1].Value is "x" or "X" });Also applies to: 36-37
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cs` around lines 21 - 22, The regex pattern in the TaskMarker() method currently allows zero or more spaces after the closing bracket followed by any content, which causes false positives like [x]foo to be matched as task items. Modify the regex pattern to require either whitespace followed by content, or no content at all after the closing bracket, ensuring that task markers without a space separator (like [x]foo) are not matched as valid task items.
🧹 Nitpick comments (1)
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs (1)
63-77: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winAdd unsafe image URI sanitization coverage alongside the link sanitization test.
Current security coverage validates unsafe link
hrefstripping, but not unsafe imagesrc. A sibling test closes that regression gap for the same sanitizer contract.Suggested test addition
+ [TestMethod] + public void BitMarkdownViewerShouldSanitizeUnsafeImageSources() + { + var component = RenderComponent<BitMarkdownViewer>(parameters => + { + parameters.Add(p => p.Markdown, ")"); + }); + + var image = component.Find(".bit-mdv img"); + var src = image.GetAttribute("src") ?? string.Empty; + Assert.IsTrue( + src.Length == 0 || !src.Contains("javascript:", StringComparison.OrdinalIgnoreCase), + $"Unsafe image src was not sanitized: '{src}'."); + }🤖 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/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs` around lines 63 - 77, Create a new test method in the BitMarkdownViewerTests class to validate unsafe image URI sanitization, mirroring the structure of the existing BitMarkdownViewerShouldSanitizeUnsafeLinks method. Render the BitMarkdownViewer component with unsafe image markdown (e.g., )), then find the rendered img element using an appropriate selector, retrieve its src attribute, and assert that the src is either empty or does not contain the javascript scheme using the same validation logic applied to link href attributes in the existing test.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cs`:
- Around line 105-115: In the SplitRow method's backtick handling logic around
lines 105-115, the code does not account for escaped backticks when determining
code-span state. Before processing backticks as code-span delimiters, check if
the backtick is escaped (preceded by a backslash character). If a backtick is
escaped, treat it as a literal character and append it without modifying the
backtickRun state. Only process unescaped backtick runs to toggle the
backtickRun value, ensuring that the row separator detection at line 114 works
correctly and cells are parsed properly.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cs`:
- Around line 21-22: The regex pattern in the TaskMarker() method currently
allows zero or more spaces after the closing bracket followed by any content,
which causes false positives like [x]foo to be matched as task items. Modify the
regex pattern to require either whitespace followed by content, or no content at
all after the closing bracket, ensuring that task markers without a space
separator (like [x]foo) are not matched as valid task items.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cs`:
- Around line 59-60: The ChildLists property in ListNode currently creates a
detached snapshot of Items using ToList(), which means AST rewrites on that
collection don't update the original ListNode.Items. Remove the ToList() call
and instead return the actual Items collection directly (wrapped in an array for
the IEnumerable interface), ensuring it remains connected to the source. Then
update all list consumers and call sites (renderer, parser, etc.) to properly
cast and validate ListItemNode items as needed when working with this
collection.
---
Nitpick comments:
In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs`:
- Around line 63-77: Create a new test method in the BitMarkdownViewerTests
class to validate unsafe image URI sanitization, mirroring the structure of the
existing BitMarkdownViewerShouldSanitizeUnsafeLinks method. Render the
BitMarkdownViewer component with unsafe image markdown (e.g.,
)), then find the rendered img element using an
appropriate selector, retrieve its src attribute, and assert that the src is
either empty or does not contain the javascript scheme using the same validation
logic applied to link href attributes in the existing test.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e4c00a84-fbe1-46a8-87e7-4ccead6b203c
📒 Files selected for processing (41)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/Bundles.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/EmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/StrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/Abstractions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreBlockParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreInlineParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/DelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/MarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cs (1)
97-107:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winHandle odd/even backslash parity when interpreting escaped table separators.
Line 104 and Line 107 currently treat any
\|/\`` pair as escaped, even when that backslash is itself escaped (e.g.\|`). This can mis-split cells and code-span state in edge cases.Proposed minimal fix
private static List<string> SplitRow(string line) { string s = line.Trim(); if (s.StartsWith('|')) s = s[1..]; - if (s.EndsWith('|') && !s.EndsWith("\\|")) s = s[..^1]; + if (s.EndsWith('|') && !IsEscapedOutsideCode(s, s.Length - 1)) s = s[..^1]; @@ - if (s[i] == '\\' && i + 1 < s.Length && s[i + 1] == '|' && backtickRun == 0) { sb.Append('|'); i++; } + if (s[i] == '\\' && i + 1 < s.Length && s[i + 1] == '|' && backtickRun == 0 && !IsEscapedOutsideCode(s, i)) { sb.Append('|'); i++; } @@ - else if (s[i] == '\\' && i + 1 < s.Length && s[i + 1] == '`' && backtickRun == 0) { sb.Append('\\'); sb.Append('`'); i++; } + else if (s[i] == '\\' && i + 1 < s.Length && s[i + 1] == '`' && backtickRun == 0 && !IsEscapedOutsideCode(s, i)) { sb.Append('\\'); sb.Append('`'); i++; } @@ cells.Add(sb.ToString()); return cells; } + + private static bool IsEscapedOutsideCode(string s, int index) + { + int slashCount = 0; + for (int j = index - 1; j >= 0 && s[j] == '\\'; j--) slashCount++; + return (slashCount & 1) == 1; + } }🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cs` around lines 97 - 107, The escape handling for pipe and backtick characters in the parsing loop does not account for backslash parity. Currently, the conditions checking s[i] == '\\' at line 104 and line 107 treat any backslash-pipe or backslash-backtick as escaped, even when the backslash itself is escaped (e.g., `\\|` or `\\``). To fix this, count the number of consecutive backslashes preceding the current position by iterating backwards from i, and only treat the pipe or backtick as escaped if the count of preceding backslashes is odd. Update both the condition check and the logic in the loop that processes these escape sequences in the ParseCells method.
🧹 Nitpick comments (3)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cs (1)
22-23: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueConsider caching the wrapped array for repeated traversals.
The default
ChildListsimplementation allocates a new single-element array on every access whenChildNodesis non-null. While most container nodes will overrideChildListsdirectly (asListNodedoes), nodes relying on this default may experience allocation pressure during repeated AST traversals.However, given that this is a fallback for simple containers and the impact is limited, the current implementation is acceptable.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cs` around lines 22 - 23, The ChildLists property in the MarkdownNode class creates a new single-element array on each access when ChildNodes is non-null, causing unnecessary allocations during repeated AST traversals. To fix this, introduce a private cached field to store the wrapped array (initialized lazily when first needed), and modify the ChildLists property to return this cached array instead of creating a new one each time. This approach maintains the same behavior while reducing allocation pressure on nodes that rely on the default ChildLists implementation.src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cs (1)
133-138: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueCode duplication:
CountRunis defined in bothInlineProcessorandInlineHelpers.This identical method exists in
InlineHelpers.CountRun(lines 9-14). Consider removing the private copy here and using the shared utility.Suggested fix
- private static int CountRun(string s, int start, char c) - { - int j = start; - while (j < s.Length && s[j] == c) j++; - return j - start; - } + private static int CountRun(string s, int start, char c) => InlineHelpers.CountRun(s, start, c);🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cs` around lines 133 - 138, The CountRun method in InlineProcessor is duplicating functionality already available in InlineHelpers.CountRun. Remove the private CountRun method from InlineProcessor class and replace all calls to this.CountRun (or any local CountRun calls) with calls to InlineHelpers.CountRun to eliminate code duplication and use the shared utility method instead.src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs (1)
24-30: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueProtocol-relative URLs (
//) may pose security risk in mixed-content scenarios.Allowing
//example.com/pathpasses through unsanitized. If the page is served over HTTP, this could load content from an attacker-controlled HTTP source. Consider whether this is intentional for your use case.🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs` around lines 24 - 30, The UrlSanitizer.cs file allows protocol-relative URLs (those starting with "//") to pass through unsanitized in the condition that checks for StartsWith("#"), StartsWith("/"), StartsWith("./"), and StartsWith("../"), which creates a security risk in mixed-content scenarios. Remove the trimmed.StartsWith("//") check from this validation condition to prevent protocol-relative URLs from being automatically allowed without additional security validation, ensuring that such URLs are either blocked or handled through a more secure validation mechanism if they need to be supported.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs`:
- Around line 43-46: The scheme extraction in the UrlSanitizer uses individual
Replace calls to strip only specific control characters, but this is incomplete
and allows XSS bypasses because it misses other C0 control characters
(0x00–0x1F) and DEL (0x7F) that browsers normalize. Replace the manual character
replacement chain on the scheme variable with a regex pattern that removes all
ASCII C0 control characters and the DEL character in a single operation,
ensuring comprehensive sanitization according to the WHATWG URL Standard.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cs`:
- Line 87: The CopyTo method lacks proper bounds validation and will throw
IndexOutOfRangeException when the destination array lacks sufficient space,
violating the ICollection<T>.CopyTo contract which requires ArgumentException.
Add a validation check before the foreach loop in the CopyTo method that
verifies array.Length - arrayIndex is greater than or equal to items.Count, and
if this condition is not met, throw an ArgumentException with an appropriate
error message describing the insufficient space in the destination array.
- Around line 57-63: The ChildLists property in the ListNode class allocates a
new array and ListItemListView wrapper object on every access, creating
significant memory pressure during AST traversal. Cache this result by creating
a private field to store the wrapper array, initialize it lazily on first access
to ChildLists, and return the cached field on subsequent accesses instead of
creating new allocations each time.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cs`:
- Around line 97-107: The escape handling for pipe and backtick characters in
the parsing loop does not account for backslash parity. Currently, the
conditions checking s[i] == '\\' at line 104 and line 107 treat any
backslash-pipe or backslash-backtick as escaped, even when the backslash itself
is escaped (e.g., `\\|` or `\\``). To fix this, count the number of consecutive
backslashes preceding the current position by iterating backwards from i, and
only treat the pipe or backtick as escaped if the count of preceding backslashes
is odd. Update both the condition check and the logic in the loop that processes
these escape sequences in the ParseCells method.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cs`:
- Around line 133-138: The CountRun method in InlineProcessor is duplicating
functionality already available in InlineHelpers.CountRun. Remove the private
CountRun method from InlineProcessor class and replace all calls to
this.CountRun (or any local CountRun calls) with calls to InlineHelpers.CountRun
to eliminate code duplication and use the shared utility method instead.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cs`:
- Around line 24-30: The UrlSanitizer.cs file allows protocol-relative URLs
(those starting with "//") to pass through unsanitized in the condition that
checks for StartsWith("#"), StartsWith("/"), StartsWith("./"), and
StartsWith("../"), which creates a security risk in mixed-content scenarios.
Remove the trimmed.StartsWith("//") check from this validation condition to
prevent protocol-relative URLs from being automatically allowed without
additional security validation, ensuring that such URLs are either blocked or
handled through a more secure validation mechanism if they need to be supported.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cs`:
- Around line 22-23: The ChildLists property in the MarkdownNode class creates a
new single-element array on each access when ChildNodes is non-null, causing
unnecessary allocations during repeated AST traversals. To fix this, introduce a
private cached field to store the wrapped array (initialized lazily when first
needed), and modify the ChildLists property to return this cached array instead
of creating a new one each time. This approach maintains the same behavior while
reducing allocation pressure on nodes that rely on the default ChildLists
implementation.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: c7dd095f-89a1-43a8-b140-19ae5c24793e
📒 Files selected for processing (41)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/AutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/Bundles.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/EmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/PipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/StrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/TaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/Abstractions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/AstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreBlockParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/CoreInlineParsers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/DelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/InlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/UrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/CoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/MarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/CoreNodes.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/MarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cs (1)
5-8: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClass doc contradicts the dispatch order. Line 6 says nodes are dispatched to the "first matching" renderer, but
WriteNodeiterates from the last registered renderer downward (last-wins), as line 26 and the pipeline builder's ordering note confirm. Fix the summary to avoid misleading future extension authors.📝 Suggested doc fix
-/// Walks an AST and dispatches each node to the first matching <see cref="BitMarkdownViewerNodeRenderer"/>. +/// Walks an AST and dispatches each node to the last registered matching <see cref="BitMarkdownViewerNodeRenderer"/> +/// (so plugin renderers can override core ones).🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cs` around lines 5 - 8, The class summary for BitMarkdownViewerMarkdownRenderer is inaccurate because WriteNode uses a last-wins renderer lookup rather than the “first matching” renderer described in the doc. Update the XML summary to match the actual dispatch behavior and align it with the renderer selection logic in WriteNode and the ordering implied by the pipeline builder so future contributors are not misled.src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cs (1)
6-18: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueConsider
Lazy<T>for thread-safe pipeline caching.
_gitHub/_advancedare lazily initialized via??=without synchronization. Under concurrent renders (e.g. multiple Blazor Server circuits) two threads can build the pipeline simultaneously. The reference assignment is atomic so this is benign (duplicate build, last writer wins), butLazy<T>expresses the intent and avoids the redundant construction.♻️ Optional: use Lazy<T>
- private static BitMarkdownViewerPipeline? _gitHub; - private static BitMarkdownViewerPipeline? _advanced; + private static readonly Lazy<BitMarkdownViewerPipeline> _gitHub = + new(() => new BitMarkdownViewerPipelineBuilder().UseGitHubFlavored().Build()); + private static readonly Lazy<BitMarkdownViewerPipeline> _advanced = + new(() => new BitMarkdownViewerPipelineBuilder().UseAdvanced().Build()); @@ - public static BitMarkdownViewerPipeline GitHub - => _gitHub ??= new BitMarkdownViewerPipelineBuilder().UseGitHubFlavored().Build(); + public static BitMarkdownViewerPipeline GitHub => _gitHub.Value; @@ - public static BitMarkdownViewerPipeline Advanced - => _advanced ??= new BitMarkdownViewerPipelineBuilder().UseAdvanced().Build(); + public static BitMarkdownViewerPipeline Advanced => _advanced.Value;🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cs` around lines 6 - 18, The GitHub and Advanced pipeline caches in BitMarkdownViewerPipelines are lazily initialized with unsynchronized nullable fields, so concurrent access can trigger duplicate builds. Replace the _gitHub and _advanced backing fields with Lazy<BitMarkdownViewerPipeline> (or an equivalent thread-safe lazy pattern) and keep the existing GitHub and Advanced accessors as the single entry points that return the cached pipeline built via BitMarkdownViewerPipelineBuilder.UseGitHubFlavored and UseAdvanced.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cs`:
- Around line 61-80: `BitMarkdownViewer.BuildRenderTree` is using
runtime-generated sequence numbers via `renderer.NextSeq()`, which breaks
Blazor’s requirement for static sequence literals. Replace every
`renderer.NextSeq()` call in this render method with fixed, consecutive integer
values in source order, keeping the existing attribute and element call
structure unchanged. Use `BuildRenderTree` and
`EffectivePipeline.CreateRenderer()` to locate the render logic and make sure
the sequence numbers remain stable across renders.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiAstProcessor.cs`:
- Around line 15-29: The public static Emoji dictionary in
BitMarkdownViewerEmojiAstProcessor creates process-wide mutable state, so one
caller’s changes affect every rendering instance. Move emoji overrides into
per-pipeline/per-processor configuration, or have
BitMarkdownViewerEmojiAstProcessor snapshot an immutable lookup when it is
constructed instead of exposing a shared writable ConcurrentDictionary. Keep the
lookup localized to the emoji processing path so customization does not leak
across circuits or components.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cs`:
- Around line 72-80: The delimiter resolution in
BitMarkdownViewerDelimiterResolver.TryCreate is skipping the closer after an
unsupported opener candidate, which can hide an earlier valid opener. When
processor.TryCreate returns no node for the current opener/closer pair, do not
advance past the closer as a final decision; instead keep searching for another
opener by continuing the opener scan while preserving the closer for later
matches. Update the logic around openersBottom, closer.Active, and closerIdx so
a rejected candidate only disqualifies that opener/closer pairing, not the whole
closer.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.cs`:
- Around line 25-44: The fenced code block parser is producing OS-dependent
content because BitMarkdownViewerFencedCodeBlockParser uses
StringBuilder.AppendLine while building the code block text. Update the parsing
loop in BitMarkdownViewerFencedCodeBlockParser so it appends a consistent
newline character explicitly instead of relying on Environment.NewLine, and keep
the final TrimTrailingNewline call as-is. This fix should be applied where the
code block content is accumulated before creating
BitMarkdownViewerCodeBlockNode, to ensure rendered output is stable across
platforms.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cs`:
- Around line 8-11: The IBitMarkdownViewerExtension contract currently allows
registering components that may hold mutable state even though
BitMarkdownViewerPipeline caches and shares them across requests. Update the
contract around Setup(BitMarkdownViewerPipelineBuilder) to explicitly require
stateless, thread-safe extensions/components, and if that cannot be guaranteed,
change the pipeline behavior so extension instances are not reused across
executions. Ensure the guidance is reflected where
BitMarkdownViewerPipelineBuilder is used so implementers know the
shared-instance requirement.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerMarkdownNode.cs`:
- Around line 22-24: The lazy cache in BitMarkdownViewerMarkdownNode.ChildLists
is not thread-safe and can race during concurrent access. Fix the property by
removing the _childLists cache entirely or replacing it with a thread-safe
initialization approach such as Lazy<T> or Interlocked.CompareExchange, keeping
the ChildNodes/ChildLists behavior unchanged while avoiding unsynchronized
writes to _childLists.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cs`:
- Around line 6-18: The GitHub and Advanced pipeline caches in
BitMarkdownViewerPipelines are lazily initialized with unsynchronized nullable
fields, so concurrent access can trigger duplicate builds. Replace the _gitHub
and _advanced backing fields with Lazy<BitMarkdownViewerPipeline> (or an
equivalent thread-safe lazy pattern) and keep the existing GitHub and Advanced
accessors as the single entry points that return the cached pipeline built via
BitMarkdownViewerPipelineBuilder.UseGitHubFlavored and UseAdvanced.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cs`:
- Around line 5-8: The class summary for BitMarkdownViewerMarkdownRenderer is
inaccurate because WriteNode uses a last-wins renderer lookup rather than the
“first matching” renderer described in the doc. Update the XML summary to match
the actual dispatch behavior and align it with the renderer selection logic in
WriteNode and the ordering implied by the pipeline builder so future
contributors are not misled.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: b7c3ae65-44ae-45b6-b967-4aa730799d14
📒 Files selected for processing (87)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerColumnAlignment.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerGitHubFlavoredExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerCodeSpanInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEmphasisDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLineBreakInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParagraphParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerThematicBreakParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerUrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerNodeRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerBlockquoteNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeBlockNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeSpanNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerDocumentNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerEmphasisNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerImageNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLineBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLinkNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemListView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerMarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerParagraphNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerStrongNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerTextNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerThematicBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cs (1)
13-13: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winBlank indented line can still start an empty code block.
A line of only indentation (e.g. four spaces) has an indent ≥ 4, so it passes this entry check and produces an empty code block. CommonMark indented code blocks cannot begin with a blank line. This was previously flagged and does not appear to be addressed in the current code.
Proposed fix
- if (BitMarkdownViewerBlockProcessor.GetIndent(lines[state.Line]) < 4) return false; + if (BitMarkdownViewerBlockProcessor.GetIndent(lines[state.Line]) < 4 + || BitMarkdownViewerBlockProcessor.IsBlank(lines[state.Line])) return 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cs` at line 13, The entry check in BitMarkdownViewerIndentedCodeBlockParser.ParseBlock currently treats any line with indent 4 or more as a valid start, which allows a blank indented line to open an empty code block. Update the initial guard in ParseBlock to also reject lines that are blank after indentation, using the existing GetIndent and line content checks around state.Line, so indented code blocks only start from non-empty content.
🧹 Nitpick comments (3)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scss (1)
34-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider a theme variable for the editor/preview border color.
#8a8886is hardcoded, while the component stylesheet uses theme tokens (e.g.$clr-brd-*). The fixed color won't adapt to dark theme, leaving an inconsistent border in the playground.🤖 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/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scss` around lines 34 - 58, The editor and preview border color is hardcoded in the Markdown viewer demo stylesheet, so it won’t adapt to theme changes. Update the .mdv-editor and .mdv-preview styles to use an existing theme token or shared border variable consistent with the other component styles (for example the same $clr-brd-* family used elsewhere), keeping the border appearance theme-aware in BitMarkdownViewerDemo.razor.scss.src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cs (1)
10-13: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value
Basiclazy initialization is not thread-safe.The class doc states pipelines are thread-safe and shared, but
_basic ??= ...can run the builder multiple times under concurrent first access (e.g. multiple Blazor Server circuits). The result is immutable so this is benign, but you can avoid the redundant build withLazy<T>.♻️ Use Lazy<T> for thread-safe single initialization
- private static BitMarkdownViewerPipeline? _basic; - - /// <summary>A pipeline with only the basic CommonMark core (no flavors).</summary> - public static BitMarkdownViewerPipeline Basic => _basic ??= new BitMarkdownViewerPipelineBuilder().Build(); + private static readonly Lazy<BitMarkdownViewerPipeline> _basic = + new(() => new BitMarkdownViewerPipelineBuilder().Build()); + + /// <summary>A pipeline with only the basic CommonMark core (no flavors).</summary> + public static BitMarkdownViewerPipeline Basic => _basic.Value;🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cs` around lines 10 - 13, The Basic pipeline initialization in BitMarkdownViewerPipeline is not thread-safe because `_basic ??= ...` can build the instance multiple times under concurrent first access. Replace the current lazy field and `Basic` property logic with a thread-safe `Lazy<BitMarkdownViewerPipeline>`-based initialization so the pipeline is created only once even when accessed concurrently.src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cs (1)
113-127: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winRollback parser side effects when an attempt is ignored.
The loop resets only
Pos. If an inline parser appends/flushed content and then returnsfalse, or returnstruewithout advancing, those side effects remain and corrupt the token stream.Proposed fix
foreach (var p in parsers) { + string literalSnapshot = _literal.ToString(); + int tokenCount = _tokens.Count; + if (p.TryParse(this)) { - handled = true; - break; + if (Pos > save) + { + handled = true; + break; + } } - Pos = save; // parser must not have advanced on failure, but be safe + + Pos = save; + _literal.Clear(); + _literal.Append(literalSnapshot); + if (_tokens.Count > tokenCount) + _tokens.RemoveRange(tokenCount, _tokens.Count - tokenCount); }🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cs` around lines 113 - 127, The parser retry logic in BitMarkdownViewerInlineProcessor.TryParse only restores Pos, so ignored parser attempts can still leave behind appended/flushed content and corrupt the token stream. Update the loop around parsers in BitMarkdownViewerInlineProcessor to snapshot and restore any parser side effects when TryParse fails or when it reports success without advancing, not just Pos; use the existing handled/Pos checks to ensure only a parser that both succeeds and consumes input is honored.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cs`:
- Around line 20-27: Task-marker detection in
BitMarkdownViewerTaskListAstProcessor is happening too late in the AST pipeline,
so escaped literals can be misread as real checkboxes. Move the recognition
logic out of the post-inline pass that inspects
BitMarkdownViewerParagraphNode/BitMarkdownViewerTextNode, and instead detect
task markers from the raw list-item source or from a parser flag attached to the
list item before inline flattening occurs. Keep the checkbox insertion and text
trimming behavior, but only apply it when the original list item was explicitly
marked as a task.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cs`:
- Around line 76-85: The StripIndent method currently removes an entire tab even
when only part of its visual width is needed, so mixed indentation can be
over-stripped. Update BitMarkdownViewerBlockProcessor.StripIndent to track the
tab’s visual width and only consume the portion needed to reach the requested
column count, preserving any remaining columns as leading spaces in the returned
substring. Keep the fix localized to StripIndent and validate behavior for
inputs like a tab followed by text with a smaller count.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cs`:
- Around line 78-92: FindLabelEnd in BitMarkdownViewerLinkInlineParser currently
counts every closing bracket, so it can terminate a link label inside backtick
code spans. Update this parser helper to track and skip inline code span regions
while scanning, so `]` characters enclosed by backticks are ignored unless they
truly close the label. Keep the existing escaping and nesting behavior intact
and adjust any related label parsing logic in BitMarkdownViewerLinkInlineParser
if needed.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cs`:
- Around line 61-62: The registration flow in BitMarkdownViewerPipelineBuilder
is leaving the builder in a poisoned state when extension.Setup(this) fails
because _extensions is updated before setup completes. Update the extension
registration path so the extension is only kept in _extensions after Setup
succeeds, or otherwise remove it from _extensions in the failure path inside the
same extension registration method to allow retries and avoid partial
registration.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cs`:
- Line 13: The entry check in
BitMarkdownViewerIndentedCodeBlockParser.ParseBlock currently treats any line
with indent 4 or more as a valid start, which allows a blank indented line to
open an empty code block. Update the initial guard in ParseBlock to also reject
lines that are blank after indentation, using the existing GetIndent and line
content checks around state.Line, so indented code blocks only start from
non-empty content.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cs`:
- Around line 113-127: The parser retry logic in
BitMarkdownViewerInlineProcessor.TryParse only restores Pos, so ignored parser
attempts can still leave behind appended/flushed content and corrupt the token
stream. Update the loop around parsers in BitMarkdownViewerInlineProcessor to
snapshot and restore any parser side effects when TryParse fails or when it
reports success without advancing, not just Pos; use the existing handled/Pos
checks to ensure only a parser that both succeeds and consumes input is honored.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cs`:
- Around line 10-13: The Basic pipeline initialization in
BitMarkdownViewerPipeline is not thread-safe because `_basic ??= ...` can build
the instance multiple times under concurrent first access. Replace the current
lazy field and `Basic` property logic with a thread-safe
`Lazy<BitMarkdownViewerPipeline>`-based initialization so the pipeline is
created only once even when accessed concurrently.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scss`:
- Around line 34-58: The editor and preview border color is hardcoded in the
Markdown viewer demo stylesheet, so it won’t adapt to theme changes. Update the
.mdv-editor and .mdv-preview styles to use an existing theme token or shared
border variable consistent with the other component styles (for example the same
$clr-brd-* family used elsewhere), keeping the border appearance theme-aware in
BitMarkdownViewerDemo.razor.scss.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 8ae9d480-334a-4762-9728-a90626c34daf
📒 Files selected for processing (87)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerColumnAlignment.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerGitHubFlavoredExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerCodeSpanInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEmphasisDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLineBreakInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParagraphParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerThematicBreakParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerUrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerNodeRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerBlockquoteNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeBlockNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeSpanNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerDocumentNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerEmphasisNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerImageNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLineBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLinkNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemListView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerMarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerParagraphNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerStrongNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerTextNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerThematicBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 14
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cs (1)
63-77: 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy liftNested markdown nodes still use runtime sequence numbers.
Line 77 delegates into
BitMarkdownViewerMarkdownRenderer.WriteNodes, and that path still assigns sequences viaNextSeq()for every nested node. The literals here only fix the outer<div>; the markdown body still misses Blazor's stable-sequence contract, so rerender diffing stays on the slow path.Verify by locating the remaining runtime sequence calls in the renderer stack; you should still see hits under the markdown renderer and node renderers.
#!/bin/bash rg -n '\bNextSeq\s*\(' src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer --iglob '*Renderer*.cs' -C1🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cs` around lines 63 - 77, The outer BitMarkdownViewer builder now uses stable literals, but the nested markdown rendering path still relies on runtime sequence generation. Update BitMarkdownViewerMarkdownRenderer.WriteNodes and the node renderer stack it calls so nested elements use fixed, deterministic sequence numbers instead of NextSeq(), matching Blazor’s stable-sequence contract throughout the markdown body.
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cs (1)
68-74: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winReuse the shared URL sanitizer for generated autolinks.
These
hrefvalues are created outside the normal inline-link path, so explicit links and autolinks can drift if only one side appliesBitMarkdownViewerUrlSanitizer. Runhrefthrough the shared sanitizer before assigningBitMarkdownViewerLinkNode.Url.🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cs` around lines 68 - 74, The autolink generation in BitMarkdownViewerAutoLinkAstProcessor builds href values without the shared sanitization path, so autolinks can differ from normal links. Update the link creation flow in the autolink processor to pass the computed href through BitMarkdownViewerUrlSanitizer before assigning it to BitMarkdownViewerLinkNode.Url, keeping the existing matched/www/email handling intact.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiExtension.cs`:
- Around line 12-17: The BitMarkdownViewerEmojiExtension constructor is storing
the passed IReadOnlyDictionary reference directly, which leaves
BitMarkdownViewerEmojiAstProcessor configuration tied to mutable external state.
Snapshot the emoji overrides inside BitMarkdownViewerEmojiExtension by copying
the incoming overrides into a new dictionary before assigning to the field, and
keep Setup using that stored snapshot when creating
BitMarkdownViewerEmojiAstProcessor.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cs`:
- Around line 46-55: The table body parsing in
BitMarkdownViewerPipeTableBlockParser is too permissive and keeps consuming
lines that should start a new block. Update the row loop in the parser logic to
stop not only on blank lines, but also when the next line is a block starter
(for example headings, quotes, lists, etc.), rather than relying on
Contains('|') alone. Use the existing BitMarkdownViewerBlockProcessor helpers
and the parser’s SplitRow/state.ParseInlines flow so normal table rows still
parse correctly while the next block is preserved.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cs`:
- Around line 30-33: The autolink logic in BitMarkdownViewerAutolinkInlineParser
is too permissive because the email branch uses a simple Contains('@') check,
which turns invalid `<...>` tokens into mailto links. Update the parser’s
email-detection branch in the method that calls Emit to validate the candidate
against the email-autolink grammar first, and only emit a mailto link when the
address is actually valid; otherwise leave the token as plain text.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cs`:
- Around line 42-46: The blockquote marker stripping in StripMarker only removes
an optional space after the leading marker, so tabs remain and break nested
parsing. Update BitMarkdownViewerBlockquoteParser.StripMarker to treat the first
character after the marker as either a space or a tab and strip it consistently,
preserving the remaining inner text for CommonMark blockquote parsing.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cs`:
- Around line 53-60: The rule-of-three check in
BitMarkdownViewerDelimiterResolver should not run for every delimiter processor,
because it can reject valid non-emphasis pairs before TryCreate(...) has a
chance to validate them. Update the delimiter matching logic in the resolver to
scope the CommonMark % 3 rule only to emphasis delimiters like * and _ (or
delegate it to a processor-specific hook), while keeping the generic pairing
flow intact for other processors such as ~~.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cs`:
- Around line 12-15: The BitMarkdownViewerEscapeInlineParser currently only
treats a backslash followed by LF as a hard break, so CRLF sequences are not
recognized. Update the escape handling in BitMarkdownViewerEscapeInlineParser to
also consume Windows line endings by checking for '\r\n' after the backslash, or
normalize line endings before this parser runs, and make sure the parser
advances state.Pos correctly for the consumed sequence.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cs`:
- Around line 24-26: The indented code block parser in
BitMarkdownViewerIndentedCodeBlockParser should not use AppendLine because it
reintroduces Environment.NewLine and makes parsed Content host-dependent. Update
the parsing loop to append explicit newline characters consistently, matching
the fenced code block normalization behavior already used elsewhere in the
markdown viewer parsing code, so the output stays stable across platforms.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cs`:
- Around line 57-70: The list parser in BitMarkdownViewerListParser is consuming
all spaces after the marker into markerIndent, which drops overflow spaces that
should remain in the item content. Update the marker handling in the ordered and
unordered branches so only the required separator space is counted as
indentation, and preserve any extra spaces by prepending them to firstContent
when computing the item’s initial content. Use the existing marker parsing logic
in BitMarkdownViewerBlockProcessor.GetIndent and the m.Groups values to keep the
content alignment correct.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cs`:
- Around line 61-70: The rollback in the Markdown viewer pipeline builder only
removes the extension from _extensions when extension.Setup(this) throws, but
any parsers, processors, or renderers registered during that setup still remain.
Update the extension registration flow in BitMarkdownViewerPipelineBuilder so
the catch fully reverts all mutations made by Setup, not just _extensions, by
tracking and undoing any additions made before the exception and keeping the
builder reusable after a failed setup.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cs`:
- Around line 8-15: The remarks in IBitMarkdownViewerExtension currently soften
the thread-safety contract by suggesting a “fresh instance per registration”
fallback, which is still unsafe because the built BitMarkdownViewerPipeline
caches and reuses registrations across parses and renders. Update the
documentation to state that anything registered from Setup must be stateless and
thread-safe, and that any mutable per-parse/per-render state must live only in
the passed state/builder objects; remove the guidance implying a stateful
parser/renderer can be made safe just by instantiating it in Setup().
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cs`:
- Around line 34-35: The fenced-code language class generation in
BitMarkdownViewerCoreRenderer’s code-block rendering only splits code.Info on a
literal space, so tabs and other whitespace can leak metadata into the class
name. Update the logic that builds the class attribute for code.Info to take the
first non-empty token across any whitespace before prefixing it with language-,
so markdown fences like the ones handled in the renderer produce a clean
language identifier.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cs`:
- Line 6: The public BitMarkdownViewerHeadingNode.Level property currently
allows any int even though it is documented to only support 1-6, so update the
init accessor to enforce that range and prevent invalid node state. Apply the
validation directly on Level in BitMarkdownViewerHeadingNode so invalid values
are rejected at construction time, keeping downstream markdown heading
generation consistent.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cs`:
- Around line 204-239: The published MarkdownViewer playground snippet is out of
sync with the live demo, so update the sample strings to match the actual UI
shown in BitMarkdownViewerDemo, including the wrapper layout, hint text, and the
Reset/Clear actions. Edit example3RazorCode and example3CsharpCode together so
the copied snippet reproduces the same toolbar, editor, preview, and supporting
controls as the rendered example. Keep the snippet aligned with the current
markup and behaviors around SetPlaygroundFlavor and the playground state
variables.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scss`:
- Around line 34-58: The split-pane styles for .mdv-editor and .mdv-preview need
to allow flex items to shrink, otherwise long content can expand the row. Update
the BitMarkdownViewerDemo styling so both panes explicitly opt into shrinking in
the flex layout by adding the appropriate minimum width constraint in the
.mdv-editor and .mdv-preview rules, keeping the content scrollable within each
pane rather than forcing overflow of the container.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cs`:
- Around line 63-77: The outer BitMarkdownViewer builder now uses stable
literals, but the nested markdown rendering path still relies on runtime
sequence generation. Update BitMarkdownViewerMarkdownRenderer.WriteNodes and the
node renderer stack it calls so nested elements use fixed, deterministic
sequence numbers instead of NextSeq(), matching Blazor’s stable-sequence
contract throughout the markdown body.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cs`:
- Around line 68-74: The autolink generation in
BitMarkdownViewerAutoLinkAstProcessor builds href values without the shared
sanitization path, so autolinks can differ from normal links. Update the link
creation flow in the autolink processor to pass the computed href through
BitMarkdownViewerUrlSanitizer before assigning it to
BitMarkdownViewerLinkNode.Url, keeping the existing matched/www/email handling
intact.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 795b456f-36ad-458f-bb77-bff99e2e82c0
📒 Files selected for processing (87)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerColumnAlignment.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerGitHubFlavoredExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerCodeSpanInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEmphasisDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLineBreakInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParagraphParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerThematicBreakParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerUrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerNodeRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerBlockquoteNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeBlockNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeSpanNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerDocumentNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerEmphasisNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerImageNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLineBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLinkNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemListView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerMarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerParagraphNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerStrongNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerTextNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerThematicBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cs (1)
34-37: 🩺 Stability & Availability | 🟠 MajorWhitespace-only info string can throw
IndexOutOfRangeException.The parser in
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.csassigns theInfostring if it is not null or empty. It usesIsNullOrEmptyat line 43, which allows strings containing only whitespace (e.g., " ", "\t") to be set as theInfovalue.In the renderer (
BitMarkdownViewerCoreRenderer.cslines 34-36), the guardIsNullOrEmptyreturns false for whitespace-only strings. Consequently,SplitwithRemoveEmptyEntriesproduces an empty array, causing[0]to throwIndexOutOfRangeExceptionand crash the rendering.Fix: Change the guard to
IsNullOrWhiteSpacein the renderer.Proposed fix
- if (!string.IsNullOrEmpty(code.Info)) - b.AddAttribute(r.NextSeq(), "class", "language-" - + code.Info.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)[0]); + if (!string.IsNullOrWhiteSpace(code.Info)) + b.AddAttribute(r.NextSeq(), "class", "language-" + + code.Info.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)[0]);🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cs` around lines 34 - 37, The Markdown renderer in BitMarkdownViewerCoreRenderer is only checking code.Info with IsNullOrEmpty, so whitespace-only info strings can still reach the language-class logic and make Split(...)[0] throw IndexOutOfRangeException. Update the guard in the rendering path that builds the "language-" CSS class to use IsNullOrWhiteSpace instead, keeping the existing code.Info handling in BitMarkdownViewerCoreRenderer consistent with the parser output from BitMarkdownViewerFencedCodeBlockParser.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cs`:
- Around line 24-34: The autolink scheme check in
BitMarkdownViewerAutolinkInlineParser is too permissive and allows
single-character schemes like drive letters to be emitted as links. Tighten the
validation in the parser’s colon/scheme guard so it requires a minimum scheme
length of 2 before calling Emit, keeping the existing character-class checks in
place.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor`:
- Around line 31-39: The flavor selector buttons in BitMarkdownViewerDemo.razor
only indicate the active choice visually through Variant, so add an accessible
pressed state to each BitButton using aria-pressed or the BitButton equivalent
and bind it to playgroundFlavor in the toggle group. Update the
example3RazorCode snippet to match the same button markup and active-state
behavior so the published code sample stays aligned with the demo.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cs`:
- Around line 234-249: The published playground snippet is missing the
SampleMarkdown definition, so the BitMarkdownViewerDemo.razor.cs example is not
self-contained and will not compile when copied. Update the example around
playgroundMarkdown and ResetPlaygroundSample to either declare SampleMarkdown
within the snippet or replace those references with the inline sample text
directly, keeping the names SetPlaygroundFlavor and ResetPlaygroundSample
intact.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cs`:
- Around line 34-37: The Markdown renderer in BitMarkdownViewerCoreRenderer is
only checking code.Info with IsNullOrEmpty, so whitespace-only info strings can
still reach the language-class logic and make Split(...)[0] throw
IndexOutOfRangeException. Update the guard in the rendering path that builds the
"language-" CSS class to use IsNullOrWhiteSpace instead, keeping the existing
code.Info handling in BitMarkdownViewerCoreRenderer consistent with the parser
output from BitMarkdownViewerFencedCodeBlockParser.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 7db8974c-a756-46c4-b450-ec7dcef1fcfc
📒 Files selected for processing (87)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerColumnAlignment.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerGitHubFlavoredExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerCodeSpanInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEmphasisDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLineBreakInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParagraphParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerThematicBreakParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerUrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerNodeRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerBlockquoteNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeBlockNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeSpanNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerDocumentNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerEmphasisNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerImageNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLineBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLinkNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemListView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerMarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerParagraphNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerStrongNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerTextNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerThematicBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cs (1)
13-29: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy liftUse stable sequence scopes instead of one global counter.
NextSeq()currently advances across the entire document, so inserting a node near the top shifts the sequence numbers for everything after it. WithRenderTreeBuilder, that throws away Blazor's diff-location hints and can cause much larger rerenders on long markdown documents. Consider regioning each rendered node/list item and resetting inner numbering, or otherwise making sequence numbers stable per render callsite instead of per render pass.🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cs` around lines 13 - 29, `BitMarkdownViewerMarkdownRenderer.NextSeq` currently uses one global counter for the whole document, which makes sequence numbers shift for all later content when earlier nodes change. Update `WriteNodes` and `WriteNode` to use stable per-callsite sequence scopes with `RenderTreeBuilder` regions, resetting numbering inside each node/list item so sequence values stay local and deterministic. Keep the fix centered around `BitMarkdownViewerMarkdownRenderer` and its rendering flow rather than a single shared `_seq` across the entire render pass.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scss`:
- Around line 105-131: Update the BitMarkdownViewer SCSS rules to use logical
properties so they respect rtl rendering from BitMarkdownViewer; replace
left-specific spacing/border declarations in the blockquote, list, and
.task-list-item-checkbox styles with logical equivalents so the layout flips
correctly when dir="rtl" is set.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cs`:
- Around line 99-123: The closing-run lookahead in HasMatchingBacktickRun is
incorrectly counting escaped backticks as valid code-span closers, which causes
SplitRow to stay in backtick mode and miss real cell separators. Update the
backtick scan in BitMarkdownViewerPipeTableBlockParser so it ignores any
backtick run immediately preceded by an escape character and only returns true
for unescaped closing runs, keeping the code-span tracking in SplitRow accurate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cs`:
- Around line 11-24: The task marker detection in
BitMarkdownViewerTaskListAstProcessor.Process is matching against the full
item.Source, which causes multi-line list items with continuation lines to fail
checkbox detection. Update the logic around TaskMarker() so it extracts and
evaluates only the first logical source line from item.Source before applying
the regex, while keeping the existing raw-source check that avoids treating
escaped literals like "\[ \]" as tasks.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cs`:
- Around line 27-33: Adjust StripClosingHashes in
BitMarkdownViewerAtxHeadingParser so it first ignores any trailing whitespace
before checking for closing # characters. The current logic only trims when the
content literally ends with hashes, so update the method to detect the hash run
after skipping spaces and then return the heading text without the closing
sequence. Keep the fix localized to StripClosingHashes and preserve the existing
whitespace-before-hashes validation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cs`:
- Around line 8-33: The block-grammar regexes in BitMarkdownViewerBlockGrammar
currently use \s in several Markdown block matchers, which lets Unicode
whitespace like NBSP open or close blocks incorrectly. Update the GeneratedRegex
patterns for ThematicBreak, AtxHeading, Fence, FenceClose, Bullet, and Ordered
to use Markdown-appropriate whitespace classes instead of \s: use [ \t] where
spaces/tabs are allowed and literal spaces where the construct is space-only.
Keep the parser behavior aligned with CommonMark so paragraph interruption and
block recognition remain correct.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cs`:
- Around line 18-23: The blockquote parsing in BitMarkdownViewerBlockquoteParser
is too permissive for lazy continuation lines, because the while loop currently
keeps any nonblank line inside the quote. Update the logic around IsQuote,
BitMarkdownViewerBlockProcessor.IsBlank, and state.StartsBlock so unmarked
continuation is accepted only while the current quoted content is still a
paragraph; once a non-paragraph block like a heading is encountered, later
unmarked lines such as “body” should fall outside the blockquote.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cs`:
- Line 49: The generic delimiter resolver is caching the wrong boundary token in
BitMarkdownViewerDelimiterResolver, causing later matches to stop at a
non-delimiter token instead of the previous delimiter. Update the logic in the
resolver’s matching flow so openersBottom[key] stores the previous delimiter
opener (or equivalent delimiter token) rather than tokens[closerIdx - 1], and
ensure the break condition in the opener scan only stops at that cached
delimiter boundary. Apply the same fix to both the main matching path and the
additional logic referenced by the later block so TryCreate(...) can still
evaluate earlier openers in the same bucket.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cs`:
- Around line 164-176: The parenthesized title parsing in
BitMarkdownViewerLinkInlineParser currently stops at the first closing
parenthesis, so nested titles are truncated. Update the title-scanning logic in
the link parsing flow to track nesting depth when closeCh is ')', while keeping
the existing quote and escape handling intact, so cases like [x](u (a (b)))
parse the full title correctly.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cs`:
- Around line 84-95: The list parsing loop in BitMarkdownViewerListParser is
leaving the outer index on the separating blank line after detecting a loose
list, which causes the next list item to be parsed as a new list. Update the
item-skipping logic in the block that handles blank lines inside the list item
scan so that, when IsSameMarker indicates the next item starts after blank
lines, the parser advances past the blank separator before the outer loop
continues. Use the existing BitMarkdownViewerBlockProcessor helpers and preserve
the loose-list behavior while ensuring the main loop in
BitMarkdownViewerListParser continues from the next marker item instead of
reprocessing the blank line.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cs`:
- Around line 63-83: The rollback in BitMarkdownViewerPipelineBuilder.Setup only
trims list tails, so a failed extension can still leave BlockParsers,
InlineParsers, DelimiterProcessors, AstProcessors, or Renderers mutated if it
inserted, removed, or reordered items before throwing. Update the Setup failure
handling to restore each snapped list to its exact pre-Setup state rather than
using Rollback truncation, and keep the _extensions cleanup in the catch so the
builder is fully reusable after a failed extension registration.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scss`:
- Line 1: The Sass import in BitMarkdownViewerDemo.razor.scss is using a partial
underscore and file extension, which violates the current Stylelint rules.
Update the `@import` to reference the _bit-css-variables.scss stylesheet via its
bare path without the leading underscore or .scss extension so it matches the
expected Sass import style and passes linting.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cs`:
- Around line 13-29: `BitMarkdownViewerMarkdownRenderer.NextSeq` currently uses
one global counter for the whole document, which makes sequence numbers shift
for all later content when earlier nodes change. Update `WriteNodes` and
`WriteNode` to use stable per-callsite sequence scopes with `RenderTreeBuilder`
regions, resetting numbering inside each node/list item so sequence values stay
local and deterministic. Keep the fix centered around
`BitMarkdownViewerMarkdownRenderer` and its rendering flow rather than a single
shared `_seq` across the entire render pass.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 99688c18-f98d-4eb9-bd65-126daa6481fb
📒 Files selected for processing (87)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerColumnAlignment.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerGitHubFlavoredExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerCodeSpanInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEmphasisDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLineBreakInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParagraphParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerThematicBreakParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerUrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerNodeRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerBlockquoteNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeBlockNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeSpanNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerDocumentNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerEmphasisNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerImageNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLineBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLinkNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemListView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerMarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerParagraphNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerStrongNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerTextNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerThematicBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cs (1)
12-16: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winHandle
\\\r\nhard breaks too.This still only recognizes
\\\n, so Windows-formatted markdown emits a literal backslash instead of a hard line break.Suggested fix
- if (i + 1 < s.Length && s[i + 1] == '\n') + if (i + 1 < s.Length && (s[i + 1] == '\n' || s[i + 1] == '\r')) { state.AppendNode(new BitMarkdownViewerLineBreakNode { Hard = true }); state.Pos = i + 2; + if (s[i + 1] == '\r' && i + 2 < s.Length && s[i + 2] == '\n') + state.Pos++; return true; }🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cs` around lines 12 - 16, The inline escape handling in BitMarkdownViewerEscapeInlineParser currently only treats backslash followed by LF as a hard break, so extend the BitMarkdownViewerEscapeInlineParser.TryParse logic to also recognize backslash followed by CRLF. Update the character checks around the existing BitMarkdownViewerLineBreakNode append so Windows line endings are consumed correctly, advancing the parser position past both characters and preserving the existing hard-break behavior.src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cs (1)
17-17: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winSkip trailing whitespace before stripping closing hashes.
StripClosingHashesstill only detects a closing#run when it touches the physical end of the string. Inputs like# foo ###therefore becomefoo ###after Line 17 trims the spaces, instead offoo.Suggested fix
private static string StripClosingHashes(string content) { - int hashStart = content.Length; + int end = content.Length; + while (end > 0 && char.IsWhiteSpace(content[end - 1])) end--; + + int hashStart = end; while (hashStart > 0 && content[hashStart - 1] == '#') hashStart--; - if (hashStart < content.Length && (hashStart == 0 || char.IsWhiteSpace(content[hashStart - 1]))) + if (hashStart < end && (hashStart == 0 || char.IsWhiteSpace(content[hashStart - 1]))) return content[..hashStart]; return content; }Also applies to: 27-33
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cs` at line 17, The ATX heading parser currently trims after calling StripClosingHashes, so trailing spaces prevent closing hashes from being removed in BitMarkdownViewerAtxHeadingParser. Update the content extraction in the heading parsing logic (including the related path around the same content handling block) so trailing whitespace is removed before StripClosingHashes is applied, and keep the final trim afterward if needed. Use the existing parser methods and symbols in BitMarkdownViewerAtxHeadingParser to ensure inputs like headings with closing hashes followed by spaces are normalized correctly.
🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cs`:
- Around line 11-17: The BitMarkdownViewerAutoLinkAstProcessor regex is
stripping valid closing delimiters from URLs because the trailing character
class in the GeneratedRegex excludes ) ] and } unconditionally. Update the
autolink matching in the BitMarkdownViewerAutoLinkAstProcessor pattern so it
captures the full URL candidate first, then trim only unmatched trailing
punctuation in the processor logic instead of baking that exclusion into the
regex. Keep the fix localized to the URL/www matching used by the auto-link AST
processor.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cs`:
- Line 62: The IsBlank helper currently uses Trim(), which treats Unicode
whitespace like NBSP as blank; update BitMarkdownViewerBlockProcessor.IsBlank so
it only considers spaces and tabs as blank. Replace the generic trimming check
with an explicit scan over the characters in line, and return true only when
every character is a regular space or tab, keeping other whitespace visible to
the block parser.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cs`:
- Around line 150-156: The ResolveContentIndent logic in
BitMarkdownViewerListParser only applies the CommonMark 5+ space handling when
firstContent is non-empty, so blank first lines after a list marker get the
wrong markerIndent. Update ResolveContentIndent to apply the “consume 1, keep
the rest” rule based on afterMarker alone, preserving the extra spaces even when
firstContent is blank, and keep the current special-case behavior consistent for
indented code blocks in list items.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cs`:
- Around line 61-85: The failed-Setup rollback in
BitMarkdownViewerPipelineBuilder only restores parser/renderer snapshots and
removes the current extension, but it leaves any nested extensions added through
Use(...) in _extensions. Snapshot and restore _extensions alongside the other
registration lists inside the Setup/try-catch flow, so a retry doesn’t
incorrectly short-circuit on a rolled-back extension and leave the builder
partially disabled.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cs`:
- Around line 14-19: The markdown render path in
BitMarkdownViewerMarkdownRenderer still uses the runtime sequence counter via
NextSeq(), so update the Write implementations in the renderer subclasses to
pass fixed literal sequence numbers directly to RenderTreeBuilder calls instead
of incrementing _seq. Remove the dependency on NextSeq() where it is used in the
render tree building flow, and use stable call-site literals (with regions if
that helps keep the sequences organized) so the sequence values remain static.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cs`:
- Around line 6-14: The Heading node’s Level can still remain at the default 0
because the init-only validation in BitMarkdownViewerHeadingNode only runs when
assigned. Update BitMarkdownViewerHeadingNode so it cannot be instantiated with
an invalid heading level, either by requiring Level in the constructor or by
initializing the backing field to a valid default before
BitMarkdownViewerCoreRenderer uses it. Ensure the fix keeps the Level property
and its validation logic aligned so no BitMarkdownViewerHeadingNode instance can
render as h0.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cs`:
- Line 17: The ATX heading parser currently trims after calling
StripClosingHashes, so trailing spaces prevent closing hashes from being removed
in BitMarkdownViewerAtxHeadingParser. Update the content extraction in the
heading parsing logic (including the related path around the same content
handling block) so trailing whitespace is removed before StripClosingHashes is
applied, and keep the final trim afterward if needed. Use the existing parser
methods and symbols in BitMarkdownViewerAtxHeadingParser to ensure inputs like
headings with closing hashes followed by spaces are normalized correctly.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cs`:
- Around line 12-16: The inline escape handling in
BitMarkdownViewerEscapeInlineParser currently only treats backslash followed by
LF as a hard break, so extend the BitMarkdownViewerEscapeInlineParser.TryParse
logic to also recognize backslash followed by CRLF. Update the character checks
around the existing BitMarkdownViewerLineBreakNode append so Windows line
endings are consumed correctly, advancing the parser position past both
characters and preserving the existing hard-break behavior.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 02e44b79-61e1-4782-bb57-57acc391583d
📒 Files selected for processing (87)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerColumnAlignment.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerGitHubFlavoredExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerCodeSpanInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEmphasisDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLineBreakInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParagraphParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerThematicBreakParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerUrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerNodeRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerBlockquoteNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeBlockNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeSpanNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerDocumentNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerEmphasisNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerImageNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLineBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLinkNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemListView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerMarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerParagraphNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerStrongNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerTextNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerThematicBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
♻️ Duplicate comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cs (1)
164-176: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winHandle balanced parentheses in
(...)titles.This loop still stops a parenthesized title at the first
), so[x](u (a (b)))parsestitle == "a (b"instead ofa (b). Track nesting depth whencloseChis).Proposed fix
if (i < n && (s[i] is '"' or '\'' or '(')) { - char closeCh = s[i] == '(' ? ')' : s[i]; + bool parenTitle = s[i] == '('; + char closeCh = parenTitle ? ')' : s[i]; i++; var tb = new StringBuilder(); + int parenDepth = 0; while (i < n && s[i] != closeCh) { if (s[i] == '\\' && i + 1 < n) { tb.Append(s[i + 1]); i += 2; continue; } + if (parenTitle) + { + if (s[i] == '(') { parenDepth++; tb.Append(s[i++]); continue; } + if (s[i] == ')' && parenDepth > 0) { parenDepth--; tb.Append(s[i++]); continue; } + } tb.Append(s[i++]); } if (i >= n) return 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cs` around lines 164 - 176, The title parsing in BitMarkdownViewerLinkInlineParser’s link inline parser stops too early for parenthesized titles. Update the title-reading loop that handles closeCh == ')' to track nested parentheses depth so cases like "[x](u (a (b)))" preserve the full title instead of truncating at the first closing parenthesis; keep the existing quote and escape handling intact while adjusting the parsing logic in this title extraction block.src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cs (1)
33-34: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Setext()still uses\s, inconsistent with the other block regexes.The earlier whitespace-normalization change converted
ThematicBreak,AtxHeading,Fence,FenceClose,Bullet, andOrderedto[ \t], butSetext()was missed.\smatches Unicode whitespace (e.g. NBSP), so a setext underline padded with NBSP can be recognized incorrectly, diverging from CommonMark and the rest of this grammar.🔧 Proposed fix
- [GeneratedRegex(@"^ {0,3}(=+|-+)\s*$")] + [GeneratedRegex(@"^ {0,3}(=+|-+)[ \t]*$")] public static partial Regex Setext();🤖 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/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cs` around lines 33 - 34, Setext() in BitMarkdownViewerBlockGrammar still uses \s, unlike the other block regexes that were updated to [ \t]. Update the GeneratedRegex pattern for Setext() to use the same ASCII whitespace handling as ThematicBreak, AtxHeading, Fence, FenceClose, Bullet, and Ordered so NBSP and other Unicode whitespace are not accepted as setext padding.
🤖 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.
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cs`:
- Around line 33-34: Setext() in BitMarkdownViewerBlockGrammar still uses \s,
unlike the other block regexes that were updated to [ \t]. Update the
GeneratedRegex pattern for Setext() to use the same ASCII whitespace handling as
ThematicBreak, AtxHeading, Fence, FenceClose, Bullet, and Ordered so NBSP and
other Unicode whitespace are not accepted as setext padding.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cs`:
- Around line 164-176: The title parsing in BitMarkdownViewerLinkInlineParser’s
link inline parser stops too early for parenthesized titles. Update the
title-reading loop that handles closeCh == ')' to track nested parentheses depth
so cases like "[x](u (a (b)))" preserve the full title instead of truncating at
the first closing parenthesis; keep the existing quote and escape handling
intact while adjusting the parsing logic in this title extraction block.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 8528068b-d183-4be5-a317-083b352967ef
📒 Files selected for processing (87)
src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csprojsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoIdentifierExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerAutoLinkExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerColumnAlignment.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerEmojiExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerGitHubFlavoredExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipeTableExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelineBuilderExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerPipelines.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerStrikethroughRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTableRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskCheckboxRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Extensions/BitMarkdownViewerTaskListExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstHelper.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAstProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAtxHeadingParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerAutolinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockGrammar.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerBlockquoteParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerCodeSpanInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerDelimiterResolver.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEmphasisDelimiterProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerEscapeInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerFencedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerIndentedCodeBlockParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerInlineProcessor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLineBreakInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerLinkInlineParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerListParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParagraphParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerThematicBreakParser.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Parsing/BitMarkdownViewerUrlSanitizer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipeline.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/BitMarkdownViewerPipelineBuilder.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Pipeline/IBitMarkdownViewerExtension.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerCoreRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerMarkdownRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Rendering/BitMarkdownViewerNodeRenderer.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerBlockquoteNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeBlockNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerCodeSpanNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerDocumentNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerEmphasisNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerHeadingNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerImageNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLineBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerLinkNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemListView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListItemNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerListNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerMarkdownNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerParagraphNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerStrongNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerTextNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/Syntax/BitMarkdownViewerThematicBreakNode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.tssrc/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.jssrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csprojsrc/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scsssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/MarkdownViewer/BitMarkdownViewerTests.cs
💤 Files with no reviewable changes (11)
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
- src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor
- src/BlazorUI/Bit.BlazorUI.Extras/Bit.BlazorUI.Extras.csproj
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
- src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Services/BitMarkdownService.cs
- src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
closes #12503
Summary by CodeRabbit