Skip to content

Commit

Permalink
Fix Issue when rendering multi-line list items (#7)
Browse files Browse the repository at this point in the history
* Simplify kitchen-sink

* Add kitchen-sink-expected.md

* Update Tests

* Replace line breaks in ListItem content with custom string

* Replace custom line breaks in ListBlockRenderer
  • Loading branch information
stefanzweifel committed Aug 1, 2023
1 parent d03cc5c commit 2a0656a
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 164 deletions.
14 changes: 14 additions & 0 deletions src/Renderer/Block/ListBlockRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): s
$content = $childRenderer->renderNodes($node->children());
$content = explode("\n", $content);

$content = array_map(fn ($item) => $this->replaceInternalLineBreakCharacter($item), $content);

if ($listData->type === ListBlock::TYPE_BULLET) {
$content = array_map(fn ($item) => "- {$item}", $content);
}
Expand All @@ -42,4 +44,16 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): s

return implode("\n", $content) . "\n";
}

/**
* Replace custom line break character with _native_ line breaks.
* Whitespace is added so that other Markdown clients correctly
* render the list and its line breaks.
* @param string $content
* @return string
*/
private function replaceInternalLineBreakCharacter(string $content): string
{
return str_replace(ListItemRenderer::INLINE_LINE_BREAK, " \n ", $content);
}
}
11 changes: 11 additions & 0 deletions src/Renderer/Block/ListItemRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

final class ListItemRenderer implements \League\CommonMark\Renderer\NodeRendererInterface
{
public const INLINE_LINE_BREAK = '_COMMONMARK_MARKDOWN_RENDERER_LINE_BREAK_';

/**
* @param ListItem $node
*
Expand All @@ -24,6 +26,15 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): s
ListItem::assertInstanceOf($node);

$contents = $childRenderer->renderNodes($node->children());

// If the ListItem contains a line break, replace the line break with a custom string.
// The custom line break string is being replaced with a _native_ line break again, when
// being rendered in a ListBlock.
// This workaround is required to support multi-line list items.
if (str_contains($contents, "\n")) {
$contents = str_replace("\n", self::INLINE_LINE_BREAK, $contents);
}

if (str_starts_with($contents, '<') && ! $this->startsTaskListItem($node)) {
$contents = "\n" . $contents;
}
Expand Down
20 changes: 19 additions & 1 deletion tests/Renderer/MarkdownRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,29 @@ public function it_renders_ast_to_markdown(): void
public function it_parses_and_renders_kitchen_sink(): void
{
$contentKitchenSink = file_get_contents(__DIR__ . '/../stubs/kitchen-sink.md');
$contentKitchenSinkExpected = file_get_contents(__DIR__ . '/../stubs/kitchen-sink-expected.md');

$document = $this->parser->parse($contentKitchenSink);

$result = $this->renderer->renderDocument($document)->getContent();

$this->assertEquals($contentKitchenSink, $result);
$this->assertEquals($contentKitchenSinkExpected, $result);
}

#[Test]
public function it_parses_kitchen_sink_and_parsing_the_result_again_returns_the_same_result(): void
{
$contentKitchenSink = file_get_contents(__DIR__ . '/../stubs/kitchen-sink.md');
$contentKitchenSinkExpected = file_get_contents(__DIR__ . '/../stubs/kitchen-sink-expected.md');

$document = $this->parser->parse($contentKitchenSink);

$result = $this->renderer->renderDocument($document)->getContent();
$this->assertEquals($contentKitchenSinkExpected, $result);

// Take the result and parse it again
$document = $this->parser->parse($result);
$result = $this->renderer->renderDocument($document)->getContent();
$this->assertEquals($contentKitchenSinkExpected, $result);
}
}
27 changes: 27 additions & 0 deletions tests/stubs/kitchen-sink-expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Changelog

All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Curiosities

- This is a list item which is followed by an indented content on the next line
which is part of the same list item
- This is a list item which contains multiple paragraphs
This is the second paragraph.
This is the third paragraph.
- This is a list item with multiple paragraphs, but without trailing whitespace in the original document at the end
This is the second paragraph.
This is the third paragraph.

## Task List

- [ ] Task 1
- [x] Task 2

## [Unreleased](https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...HEAD)

**This Text is Bold**
*This Text is Italic*

`\Class->getFoo()`
177 changes: 14 additions & 163 deletions tests/stubs/kitchen-sink.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
# Changelog

All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Curiosities

- This is a list item which is followed by an indented content on the next line
which is part of the same list item
- This is a list item which contains multiple paragraphs
This is the second paragraph.
This is the third paragraph.
- This is a list item with multiple paragraphs, but without trailing whitespace in the original document at the end
This is the second paragraph.
This is the third paragraph.

## Task List

Expand All @@ -12,165 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased](https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...HEAD)

## [1.0.0](https://github.com/olivierlacan/keep-a-changelog/compare/v0.3.0...v1.0.0) - 2017-06-20

### Added

- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
- Version navigation.
- Links to latest released version in previous versions.
- "Why keep a changelog?" section.
- "Who needs a changelog?" section.
- "How do I make a changelog?" section.
- "Frequently Asked Questions" section.
- New "Guiding Principles" sub-section to "How do I make a changelog?".
- Simplified and Traditional Chinese translations from [@tianshuo](https://github.com/tianshuo).
- German translation from [@mpbzh](https://github.com/mpbzh) & [@Art4](https://github.com/Art4).
- Italian translation from [@azkidenz](https://github.com/azkidenz).
- Swedish translation from [@magol](https://github.com/magol).
- Turkish translation from [@karalamalar](https://github.com/karalamalar).
- French translation from [@zapashcanon](https://github.com/zapashcanon).
- Brazilian Portugese translation from [@Webysther](https://github.com/Webysther).
- Polish translation from [@amielucha](https://github.com/amielucha) & [@m-aciek](https://github.com/m-aciek).
- Russian translation from [@aishek](https://github.com/aishek).
- Czech translation from [@h4vry](https://github.com/h4vry).
- Slovak translation from [@jkostolansky](https://github.com/jkostolansky).
- Korean translation from [@pierceh89](https://github.com/pierceh89).
- Croatian translation from [@porx](https://github.com/porx).
- Persian translation from [@Hameds](https://github.com/Hameds).
- Ukrainian translation from [@osadchyi-s](https://github.com/osadchyi-s).

### Changed

- Start using "changelog" over "change log" since it's the common usage.
- Start versioning based on the current English version at 0.3.0 to help
- translation authors keep things up-to-date.
- Rewrite "What makes unicorns cry?" section.
- Rewrite "Ignoring Deprecations" sub-section to clarify the ideal
- scenario.
- Improve "Commit log diffs" sub-section to further argument against
- them.
- Merge "Why can’t people just use a git log diff?" with "Commit log
- diffs"
- Fix typos in Simplified Chinese and Traditional Chinese translations.
- Fix typos in Brazilian Portuguese translation.
- Fix typos in Turkish translation.
- Fix typos in Czech translation.
- Fix typos in Swedish translation.
- Improve phrasing in French translation.
- Fix phrasing and spelling in German translation.

### Removed

- Section about "changelog" vs "CHANGELOG".

## [0.3.0](https://github.com/olivierlacan/keep-a-changelog/compare/v0.2.0...v0.3.0) - 2015-12-03

### Added

- RU translation from [@aishek](https://github.com/aishek).
- pt-BR translation from [@tallesl](https://github.com/tallesl).
- es-ES translation from [@ZeliosAriex](https://github.com/ZeliosAriex).

## [0.2.0](https://github.com/olivierlacan/keep-a-changelog/compare/v0.1.0...v0.2.0) - 2015-10-06

### Changed

- Remove exclusionary mentions of "open source" since this project can
- benefit both "open" and "closed" source projects equally.

## [0.1.0](https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.8...v0.1.0) - 2015-10-06

### Added

- Answer "Should you ever rewrite a change log?".

### Changed

- Improve argument against commit logs.
- Start following [SemVer](https://semver.org) properly.

## [0.0.8](https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.7...v0.0.8) - 2015-02-17

### Changed

- Update year to match in every README example.
- Reluctantly stop making fun of Brits only, since most of the world
- writes dates in a strange way.

### Fixed

- Fix typos in recent README changes.
- Update outdated unreleased diff link.

## [0.0.7](https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.6...v0.0.7) - 2015-02-16

### Added

- Link, and make it obvious that date format is ISO 8601.

### Changed

- Clarified the section on "Is there a standard change log format?".

### Fixed

- Fix Markdown links to tag comparison URL with footnote-style links.

## [0.0.6](https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.5...v0.0.6) - 2014-12-12

### Added

- README section on "yanked" releases.

## [0.0.5](https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.4...v0.0.5) - 2014-08-09

### Added

- Markdown links to version tags on release headings.
- Unreleased section to gather unreleased changes and encourage note
- keeping prior to releases.

## [0.0.4](https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.3...v0.0.4) - 2014-08-09

### Added

- Better explanation of the difference between the file ("CHANGELOG")
- and its function "the change log".

### Changed

- Refer to a "change log" instead of a "CHANGELOG" throughout the site
- to differentiate between the file and the purpose of the file — the
- logging of changes.

### Removed

- Remove empty sections from CHANGELOG, they occupy too much space and
- create too much noise in the file. People will have to assume that the
- missing sections were intentionally left out because they contained no
- notable changes.

## [0.0.3](https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.2...v0.0.3) - 2014-08-09

### Added

- "Why should I care?" section mentioning The Changelog podcast.

## [0.0.2](https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.1...v0.0.2) - 2014-07-10

### Added

- Explanation of the recommended reverse chronological release ordering.

## [0.0.1](https://github.com/olivierlacan/keep-a-changelog/releases/tag/v0.0.1) - 2014-05-31

### Added
**This Text is Bold**
*This Text is Italic*

- This CHANGELOG file to hopefully serve as an evolving example of a
- standardized open source project CHANGELOG.
- CNAME file to enable GitHub Pages custom domain
- README now contains answers to common questions about CHANGELOGs
- Good examples and basic guidelines, including proper date formatting.
- Counter-examples: "What makes unicorns cry?"
- `\Class->getFoo()`
`\Class->getFoo()`

0 comments on commit 2a0656a

Please sign in to comment.