Skip to content

MM-68425 Harden markdown bracket parsing#26

Open
BenCookie95 wants to merge 4 commits into
masterfrom
mm-68425-bracket-parsing
Open

MM-68425 Harden markdown bracket parsing#26
BenCookie95 wants to merge 4 commits into
masterfrom
mm-68425-bracket-parsing

Conversation

@BenCookie95
Copy link
Copy Markdown

@BenCookie95 BenCookie95 commented May 6, 2026

Summary

  • Harden markdown bracket parsing.

Ticket Link

https://mattermost.atlassian.net/browse/MM-68425

Test Plan

  • npm test

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 12eea39a-5b5a-4e45-8998-982a12b4442c

📥 Commits

Reviewing files that changed from the base of the PR and between cdbfe56 and ac58045.

📒 Files selected for processing (2)
  • lib/marked.js
  • test/tests/catastrophic.text
✅ Files skipped from review due to trivial changes (1)
  • test/tests/catastrophic.text
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/marked.js

📝 Walkthrough

Walkthrough

Inline link parsing in lib/marked.js was refactored: bracketed content is now captured with separate label/ref/href regex components and new internal tokens (_inlineLabel, _blockLabel, _href) were added and wired into inline rule expansions. A malformed link line was added to test/tests/catastrophic.text.

Changes

Inline parsing and test update

Layer / File(s) Summary
Refactor inline captures
lib/marked.js
Inline link, reflink, and nolink regex rules now use explicit label (and ref) named captures instead of a shared inside capture.
New internal regex tokens & rewiring
lib/marked.js
Added _inlineLabel, _blockLabel, and _href tokens and rewired inline rule expansions to substitute label/ref/href; removed prior _inside-based reflink wiring.
Catastrophic fixture update
test/tests/catastrophic.text
Inserted a malformed Markdown link line with nested code-span-like content pointing to http://example.com/url.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'MM-68425 Harden markdown bracket parsing' directly and specifically summarizes the main change: improving the robustness of markdown bracket parsing logic in the marked.js library.
Description check ✅ Passed The description is related to the changeset—it mentions hardening markdown bracket parsing, which aligns with the updates to inline link-reference parsing rules in lib/marked.js and the new test case in the catastrophic.text fixture.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mm-68425-bracket-parsing

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
test/index.js (2)

610-611: 💤 Low value

The argv parameter is unused.

The main function signature accepts argv but line 611 calls parseArg() with no arguments. parseArg internally uses process.argv.slice(2) regardless of what's passed.

This makes the function signature misleading and prevents testing main with custom arguments.

♻️ Either remove the unused parameter or wire it through

Option A: Remove unused parameter

-function main(argv, callback) {
+function main(callback) {
   var opt = parseArg();

Option B: Pass argv to parseArg (requires updating parseArg too)

 function main(argv, callback) {
-  var opt = parseArg();
+  var opt = parseArg(argv);

And update parseArg:

 function parseArg(argv) {
-  var argv = process.argv.slice(2)
+  argv = argv || process.argv.slice(2);
🤖 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 `@test/index.js` around lines 610 - 611, The main function currently declares
an unused argv parameter; either remove argv from main's signature to avoid the
misleading parameter, or wire it through by changing main to pass argv into
parseArg and then update parseArg to accept an argv parameter and use that
(falling back to process.argv.slice(2) when argv is undefined) so tests can
supply custom args; locate the functions main and parseArg in the file and apply
one of these two changes consistently.

199-214: 💤 Low value

Callback invocation has inconsistent argument count.

The callback is invoked with different signatures depending on the code path:

  • Line 203: callback(ok) — single argument
  • Line 210: callback(!err, err) — two arguments

While this works (the CLI callback handles err being undefined), it's inconsistent and could confuse future maintainers or callers expecting a stable signature.

♻️ Suggested fix for consistent callback signature
 function runDefaultTests(options, callback) {
   var ok = runTests(options);
 
   if (!ok || options.filter) {
-    if (callback) callback(ok);
+    if (callback) callback(ok, null);
     return ok;
   }
 
   if (!callback) return ok;
 
   bracketParsing(function(err) {
     callback(!err, err);
   });
 
   return null;
 }
🤖 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 `@test/index.js` around lines 199 - 214, The callback in runDefaultTests has
inconsistent signatures (callback(ok) vs callback(!err, err)); make them uniform
by always calling the callback with (err, result) or (error, ok) consistently:
treat the first parameter as an error and second as the boolean result. Update
the branch that currently calls callback(ok) to call callback(null, ok) (or
callback(undefined, ok)), and ensure the bracketParsing branch calls
callback(err || null, !err) so both paths use the same (error, result)
signature; adjust any callers if they expect the old order.
🤖 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.

Nitpick comments:
In `@test/index.js`:
- Around line 610-611: The main function currently declares an unused argv
parameter; either remove argv from main's signature to avoid the misleading
parameter, or wire it through by changing main to pass argv into parseArg and
then update parseArg to accept an argv parameter and use that (falling back to
process.argv.slice(2) when argv is undefined) so tests can supply custom args;
locate the functions main and parseArg in the file and apply one of these two
changes consistently.
- Around line 199-214: The callback in runDefaultTests has inconsistent
signatures (callback(ok) vs callback(!err, err)); make them uniform by always
calling the callback with (err, result) or (error, ok) consistently: treat the
first parameter as an error and second as the boolean result. Update the branch
that currently calls callback(ok) to call callback(null, ok) (or
callback(undefined, ok)), and ensure the bracketParsing branch calls
callback(err || null, !err) so both paths use the same (error, result)
signature; adjust any callers if they expect the old order.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64d0c2e6-c826-4e09-b260-6043d5f82798

📥 Commits

Reviewing files that changed from the base of the PR and between e4a8785 and 6532ed7.

📒 Files selected for processing (3)
  • lib/marked.js
  • test/bracket_parsing.js
  • test/index.js

Co-authored-by: Cursor <cursoragent@cursor.com>
@BenCookie95 BenCookie95 force-pushed the mm-68425-bracket-parsing branch from 6532ed7 to 94021d2 Compare May 6, 2026 20:51
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
lib/marked.js (1)

521-521: ⚡ Quick win

Add regression fixtures for the new _inside branches.

This hardening looks good, but this regex is easy to regress. Please add targeted cases for escaped brackets, escaped backslashes, and backtick spans inside link labels to lock expected parsing behaviour.

🤖 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 `@lib/marked.js` at line 521, The new inline._inside regex introduced to
tighten parsing has extra branches that are easy to regress; add focused
regression fixtures that assert correct parsing of link labels containing
escaped brackets (e.g., "\[" and "\]"), escaped backslashes (e.g., "\\\\"
sequences) and backtick spans inside labels (e.g., "`code`" within "[...]"
labels). Create tests that feed markdown snippets into the parser and assert the
produced token stream or rendered HTML matches the expected output for each
case, referencing the inline._inside behavior and ensuring the three scenarios
(escaped brackets, escaped backslashes, backtick spans) are covered as separate
assertions so future changes to inline._inside will be caught.
🤖 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.

Nitpick comments:
In `@lib/marked.js`:
- Line 521: The new inline._inside regex introduced to tighten parsing has extra
branches that are easy to regress; add focused regression fixtures that assert
correct parsing of link labels containing escaped brackets (e.g., "\[" and
"\]"), escaped backslashes (e.g., "\\\\" sequences) and backtick spans inside
labels (e.g., "`code`" within "[...]" labels). Create tests that feed markdown
snippets into the parser and assert the produced token stream or rendered HTML
matches the expected output for each case, referencing the inline._inside
behavior and ensuring the three scenarios (escaped brackets, escaped
backslashes, backtick spans) are covered as separate assertions so future
changes to inline._inside will be caught.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3966baee-3dbb-4d18-b40b-ab85f6441da4

📥 Commits

Reviewing files that changed from the base of the PR and between 6532ed7 and 94021d2.

📒 Files selected for processing (1)
  • lib/marked.js

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@lib/marked.js`:
- Around line 498-499: The composite bracket-matching regex is broken because
inline._inside currently only treats single-backtick code spans as opaque, so
update inline._inside to support variable-length backtick fences the same way
inline.code does (i.e., capture the opening backtick sequence and use a
backreference to match the identical closing fence, preventing premature ]
matches) or else extract the bracket scanning out of the composite regex and
perform incremental scanning that skips any code span using inline.code logic;
update the patterns referenced (inline._inside and inline.code) and add the
regression test from the comment demonstrating `[``a]b``](...)` to ensure
multi-backtick code spans do not terminate bracket parsing.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a324344d-c18d-46a2-a570-d21be55d1ece

📥 Commits

Reviewing files that changed from the base of the PR and between 94021d2 and 5da80f8.

📒 Files selected for processing (1)
  • lib/marked.js

Comment thread lib/marked.js Outdated
Co-authored-by: Cursor <cursoragent@cursor.com>
@BenCookie95
Copy link
Copy Markdown
Author

@hmhealey @edgarbellot mattermost/mattermost#36710 has the commit if you want to conduct some testing

Copy link
Copy Markdown
Member

@hmhealey hmhealey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a test case for this in test/tests/catastrophic.text? There's no expected output for that one. The tester just makes sure it completes quickly

Comment thread lib/marked.js Outdated
Comment thread lib/marked.js Outdated
Comment thread lib/marked.js Outdated
Comment on lines 521 to 525
inline._inside = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`+[^`]*?`+(?!`)|[^\[\]\\`])*/;
inline._label = /(?:\\.|[^\[\]\\])*/;
inline._href = /(?:[^()]|\([^()]*\)|\((?:[^()]*\([^()]*\))+[^()]*\))*/;
inline.link = replace(inline.link)
('inside', inline._inside)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
inline._inside = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`+[^`]*?`+(?!`)|[^\[\]\\`])*/;
inline._label = /(?:\\.|[^\[\]\\])*/;
inline._href = /(?:[^()]|\([^()]*\)|\((?:[^()]*\([^()]*\))+[^()]*\))*/;
inline.link = replace(inline.link)
('inside', inline._inside)
const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`+[^`]*?`+(?!`)|[^\[\]\\`])*/;
const _blockLabel = /(?:\\.|[^\[\]\\])*/;
inline._href = /(?:[^()]|\([^()]*\)|\((?:[^()]*\([^()]*\))+[^()]*\))*/;
inline.link = replace(inline.link)
('inside', _inlineLabel)

Comment thread lib/marked.js Outdated
Co-authored-by: Cursor <cursoragent@cursor.com>
@BenCookie95
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@BenCookie95 BenCookie95 requested a review from hmhealey May 27, 2026 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants