Skip to content

fix: do not add a newline to an empty code block - #4073

Merged
UziTech merged 2 commits into
markedjs:masterfrom
Kjubikstronk:fix-empty-code-block-newline
Sep 4, 2026
Merged

fix: do not add a newline to an empty code block#4073
UziTech merged 2 commits into
markedjs:masterfrom
Kjubikstronk:fix-empty-code-block-newline

Conversation

@Kjubikstronk

Copy link
Copy Markdown
Contributor

Marked version: 18.0.11 (53cb13f)

Markdown flavor: CommonMark

Description

Renderer.code appends a newline unconditionally:

const code = text.replace(other.endingNewline, '') + '\n';

For a code block with no content that turns '' into '\n', so an empty fence renders as <pre><code>\n</code></pre> instead of <pre><code></code></pre>.

The lexer is not involved. new Lexer({gfm: false}).lex('```\n') already gives text: ''.

Expectation


renders `<pre><code></code></pre>`

## Result

renders `<pre><code>\n</code></pre>`

## What was attempted

This fixes four CommonMark examples, all empty fenced code blocks: 126 (unclosed fence), 130 (closed fence), 144 (empty fence with an info string) and 237 (empty fence inside a block quote). I diffed the exact-match failure set across the whole spec before and after: those four move to passing and nothing else changes, in both the CommonMark and GFM runs.

Worth flagging why this went unnoticed, since it applies to more than this bug. `htmlIsEqual` builds `@markedjs/html-differ` with only `ignoreSelfClosingSlash` and `ignoreComments`, so `ignoreWhitespaces` stays at its default of `true`. Whitespace inside `pre`/`code` is significant, so all four of these were already reported as passing and carry no `shouldFail` flag. That also means the spec suite cannot protect this fix, which is why the tests below assert exact output instead.

There is a second, separate case the same blind spot hides: example 318, a fenced block in a list item, expects `b\n\n\n` and gets `b\n\n`. That one is a lexer issue rather than a renderer one, since the code token already comes out as `b\n\n`, so I have left it out of this PR.

## Contributor

- [x] Test(s) exist to ensure functionality and minimize regression (if no tests added, list tests covering this PR); or,
- [ ] no tests required for this PR.
- [ ] If submitting new feature, it has been documented in the appropriate places.

Four tests in `test/unit/marked.test.js` under `empty code block`. Three of them fail without the change and one non-empty case acts as a control. Full spec suite (1789) and unit suite (195) pass.

## 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](https://www.conventionalcommits.org/).

Renderer.code appended a newline unconditionally, so a code block with no
content rendered as <pre><code>\n</code></pre> instead of
<pre><code></code></pre>.

This fixes CommonMark examples 126, 130, 144 and 237. The spec suite did not
catch it because htmlIsEqual leaves html-differ's ignoreWhitespaces at its
default of true, and whitespace inside pre/code is significant, so all four
were already reported as passing.
@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

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

A member of the Team first needs to authorize it.

@UziTech UziTech left a comment

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.

move tests to test/specs/new with renderExact

Uses renderExact so the fixture compares exactly, which htmlIsEqual
does not, and keeps the assertions out of marked.test.js.
@Kjubikstronk

Copy link
Copy Markdown
Contributor Author

Moved to test/specs/new/empty_code_block.md with renderExact in 474ae05, and marked.test.js is untouched again.

One fixture covers all four cases. The unclosed fence has to come last since it runs to EOF. Reverting the renderer change fails it, so it has teeth.

@vercel

vercel Bot commented Sep 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
marked-website Ready Ready Preview Sep 3, 2026 3:48am UTC

Request Review

@UziTech UziTech left a comment

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.

Thanks! 💯

@UziTech
UziTech merged commit 23b1706 into markedjs:master Sep 4, 2026
8 checks passed
github-actions Bot pushed a commit that referenced this pull request Sep 7, 2026
## [18.0.12](v18.0.11...v18.0.12) (2026-09-07)

### Bug Fixes

* allow a tab before the closing sequence of an ATX heading ([#4084](#4084)) ([4417582](4417582))
* allow one more level of nested brackets in a link label ([#4064](#4064)) ([37b28d8](37b28d8))
* do not add a newline to an empty code block ([#4073](#4073)) ([23b1706](23b1706))
* escape character references in autolink destinations ([#4053](#4053)) ([8f432f0](8f432f0))
* reject GFM email autolink when the domain ends in _ or - ([#4063](#4063)) ([df57534](df57534))
* reject invalid characters in HTML tag names ([#4083](#4083)) ([300bb1d](300bb1d))
* remove up to the fence indentation from each content line ([#4074](#4074)) ([0244f08](0244f08))
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.

3 participants