Skip to content

Conversation

@tishajain25
Copy link
Contributor

Marked version: 16.4.0

Markdown flavor: CommonMark

Description
Fixes #2832 - Render bullet-pointed incorrectly
The issue was that nested lists with 4-space indentation were not being parsed correctly. When users indented nested list items with 4 spaces (which is common in some editors), the parser would incorrectly treat the nested bullet as part of the parent list item's content, leading to malformed HTML output where nested bullets were rendered as headings instead of proper nested lists.

Expectation
Nested lists with 4-space indentation should render as proper nested HTML lists:

<li>title<ul>
<li>desc</li>
<li></li>
</ul>
</li>
</ul>

Result
Previously, 4-space indented nested lists would produce incorrect output like:

<li><h2>title
  - desc</h2>
</li>
</ul>

What was attempted
The root cause was that the regex patterns for list markers in rules.ts only allowed 0-3 spaces before bullet markers, but CommonMark parsing should be more lenient to handle various indentation styles. Updated the following regexes to allow 0-4 spaces:

list regex: ^( {0,4}bull)
listItemRegex: ^( {0,4}${bull})
nextBulletRegex: ^ {0,4}(?:[*+-]|\d{1,9}[.)])
hrRegex: ^ {0,4}((?:- *){3,}|(?:_ ){3,}|(?:\ ){3,})
fencesBeginRegex: ^ {0,4}(?:`|~~~)
headingBeginRegex: ^ {0,4}#
htmlBeginRegex: ^ {0,4}<(?:[a-z].
>|!--)
Contributor
Test(s) exist to ensure functionality and minimize regression (all existing spec and unit tests pass)
no tests required for this PR.
Committer
In most cases, this should be a different person than the contributor.

CI is green (no forced merge required).
Squash and Merge PR following conventional commit guidelines.

Fixes issue markedjs#2832 - Render bullet-pointed incorrectly

The issue was that nested lists with 4-space indentation were not being
parsed correctly, causing nested bullets to be rendered as headings
instead of proper nested lists.

Updated regex patterns in src/rules.ts to allow 0-4 spaces before list
markers, horizontal rules, fences, headings, and HTML blocks to be more
lenient with indentation styles.

Added test case to prevent regression.
@vercel
Copy link

vercel bot commented Oct 17, 2025

@tishajain25 is attempting to deploy a commit to the MarkedJS Team on Vercel.

A member of the Team first needs to authorize it.

@gemini-code-assist
Copy link

Summary of Changes

Hello @tishajain25, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a parsing defect in the Markdown renderer that caused nested bulleted lists with 4-space indentation to render incorrectly. The core change involves updating regular expressions responsible for identifying list markers and other block-level elements to correctly interpret 4-space leading indentation, thereby ensuring proper CommonMark compliance and accurate HTML generation for such list structures. A new test file has been added to confirm the fix.

Highlights

  • Bug Fix for Nested Lists: Addresses an issue where nested lists with 4-space indentation were incorrectly parsed, resulting in malformed HTML output (e.g., nested bullets rendered as headings instead of proper nested lists).
  • Regex Pattern Update: Modified several regex patterns in src/rules.ts to allow for up to 4 leading spaces (instead of the previous 3) for list markers and other block elements, aligning with CommonMark's leniency for indentation.
  • New Test Case: Introduced test-bullet-issue.js to specifically validate the correct rendering of nested lists with both 2-space and 4-space indentations, ensuring the fix works as expected and prevents regressions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request aims to fix an issue with 4-space indented nested lists. The approach of modifying the regexes is correct, but some changes introduce new issues. Specifically, allowing a list to start with 4 spaces of indentation violates the CommonMark spec and can cause conflicts with code block parsing. Additionally, several regexes have been changed to use a hardcoded indentation limit, which removes important contextual information and should be revised to use a dynamic limit based on the parent list's indentation. I've also added a suggestion to improve the new test file by adding automated assertions and moving it to the correct directory. Overall, a good fix but needs some adjustments for correctness and robustness.

src/rules.ts Outdated
Comment on lines 71 to 75
nextBulletRegex: (indent: number) => new RegExp(`^ {0,4}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),
hrRegex: (indent: number) => new RegExp(`^ {0,4}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),
fencesBeginRegex: (indent: number) => new RegExp(`^ {0,4}(?:\`\`\`|~~~)`),
headingBeginRegex: (indent: number) => new RegExp(`^ {0,4}#`),
htmlBeginRegex: (indent: number) => new RegExp(`^ {0,4}<(?:[a-z].*>|!--)`, 'i'),

Choose a reason for hiding this comment

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

high

Replacing the dynamic indentation limit Math.min(3, indent - 1) with a hardcoded {0,4} for these regular expressions seems incorrect. While the original logic was flawed because it incorrectly capped indentation at 3 spaces, using a static value of 4 spaces loses the important context of the parent list's indentation level (indent). This can lead to incorrect parsing of nested structures in lists with varying indentation.

A better approach would be to fix the dynamic calculation by removing the Math.min(3, ...) part, which was the source of the original bug. A possible fix would be to use a limit based on indent, which would correctly handle nested items based on their parent's indentation.

.getRegex();

const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/)
const list = edit(/^( {0,4}bull)([ \t][^\n]+?)?(?:\n|$)/)

Choose a reason for hiding this comment

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

high

According to the CommonMark specification, a list marker can be indented by a maximum of 3 spaces. An indentation of 4 or more spaces should be interpreted as a code block. Changing this regex to allow 4 spaces ({0,4}) violates the spec and could lead to ambiguous parsing where indented code blocks are misinterpreted as lists. Please revert this to {0,3} to maintain CommonMark compliance.

Suggested change
const list = edit(/^( {0,4}bull)([ \t][^\n]+?)?(?:\n|$)/)
const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/)

Comment on lines 1 to 30
// Test case for issue #2832 - bullet rendering with 4-space indentation
import { marked } from './lib/marked.esm.js';

const testCases = [
{
name: 'Empty nested item with 4-space indentation',
markdown: `- title
- desc
-`,
},
{
name: 'Empty nested item with 2-space indentation',
markdown: `- title
- desc
-`,
},
];

testCases.forEach((testCase) => {
console.log(`\n=== ${testCase.name} ===`);
console.log('Input:');
console.log(JSON.stringify(testCase.markdown));
console.log('\nOutput:');
try {
const result = marked.parse(testCase.markdown);
console.log(result);
} catch (error) {
console.error('Error:', error.message);
}
}); No newline at end of file

Choose a reason for hiding this comment

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

medium

Thank you for adding a test case for this fix! To improve the test suite's robustness and maintainability, could you please consider the following improvements?

  1. Automate assertions: Currently, the test logs output to the console, requiring manual verification. It would be better to use assertions (like assert.deepEqual used in test/unit/Lexer.test.js) to automatically verify that the output matches the expected result. This makes the test self-contained and easier to run as part of an automated CI process.
  2. Test file location: This new test file is in the root directory. It would be great to move it into the test/unit/ directory to keep the project structure organized and consistent with other tests. You could even add these test cases to the existing test/unit/Lexer.test.js file.

This will make the new test more effective at preventing future regressions.

- Revert list regex to {0,3} for CommonMark compliance
- Update dynamic regexes to use {0,} for proper indentation handling
- Add test for nested list indentation
- Update test expectations to match correct parsing behavior
@UziTech
Copy link
Member

UziTech commented Oct 18, 2025

The tests aren't passing

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.

Render bullet-pointed incorrectly

2 participants