From 6294d44b09add8a894f30bfe7271444a0598e1bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 00:10:13 +0000 Subject: [PATCH 1/5] Update actions/checkout action to v4 (#1057) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e12925c1a..a8fa4b05b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -114,7 +114,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: From 73e129e900792be8721c1de127d91139d15833ad Mon Sep 17 00:00:00 2001 From: Colin O'Dell Date: Sun, 29 Dec 2024 08:57:42 -0500 Subject: [PATCH 2/5] Rendered list items should only add newlines around block-level children --- CHANGELOG.md | 4 + .../Renderer/Block/ListItemRenderer.php | 18 ++- tests/functional/CMarkRegressionTest.php | 6 - .../functional/CommonMarkJSRegressionTest.php | 13 +-- .../Autolink/UrlAutolinkParserTest.php | 4 +- tests/functional/Extension/Footnote/spec.txt | 9 +- .../TableOfContents/md/custom-class.html | 7 +- .../md/headings-with-inlines.html | 12 +- .../TableOfContents/md/html-in-headings.html | 4 +- .../Extension/TableOfContents/md/min-max.html | 13 +-- .../md/position-before-headings.html | 7 +- .../md/position-placeholder-multiple.html | 22 +--- .../TableOfContents/md/position-top.html | 7 +- .../Extension/TableOfContents/md/sample.html | 62 +++------- .../TableOfContents/md/setext-headings.html | 7 +- .../TableOfContents/md/style-bullet.html | 25 ++--- .../TableOfContents/md/style-ordered.html | 25 ++--- .../TableOfContents/md/weird-as-is.html | 46 +++----- .../TableOfContents/md/weird-flattened.html | 52 +++------ .../TableOfContents/md/weird-relative.html | 106 +++++------------- .../TaskList/TaskListExtensionTest.php | 11 +- 21 files changed, 135 insertions(+), 325 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd29b5e2d..e3848f261 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Updates should follow the [Keep a CHANGELOG](https://keepachangelog.com/) princi ## [Unreleased][unreleased] +### Fixed + +- Rendered list items should only add newlines around block-level children (#1059, #1061) + ## [2.6.0] - 2024-12-07 This is a **security release** to address potential denial of service attacks when parsing specially crafted, diff --git a/src/Extension/CommonMark/Renderer/Block/ListItemRenderer.php b/src/Extension/CommonMark/Renderer/Block/ListItemRenderer.php index 570f5a7f7..543baad83 100644 --- a/src/Extension/CommonMark/Renderer/Block/ListItemRenderer.php +++ b/src/Extension/CommonMark/Renderer/Block/ListItemRenderer.php @@ -17,8 +17,9 @@ namespace League\CommonMark\Extension\CommonMark\Renderer\Block; use League\CommonMark\Extension\CommonMark\Node\Block\ListItem; -use League\CommonMark\Extension\TaskList\TaskListItemMarker; +use League\CommonMark\Node\Block\AbstractBlock; use League\CommonMark\Node\Block\Paragraph; +use League\CommonMark\Node\Block\TightBlockInterface; use League\CommonMark\Node\Node; use League\CommonMark\Renderer\ChildNodeRendererInterface; use League\CommonMark\Renderer\NodeRendererInterface; @@ -39,11 +40,14 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): \ ListItem::assertInstanceOf($node); $contents = $childRenderer->renderNodes($node->children()); - if (\substr($contents, 0, 1) === '<' && ! $this->startsTaskListItem($node)) { + + $inTightList = ($parent = $node->parent()) && $parent instanceof TightBlockInterface && $parent->isTight(); + + if ($this->needsBlockSeparator($node->firstChild(), $inTightList)) { $contents = "\n" . $contents; } - if (\substr($contents, -1, 1) === '>') { + if ($this->needsBlockSeparator($node->lastChild(), $inTightList)) { $contents .= "\n"; } @@ -65,10 +69,12 @@ public function getXmlAttributes(Node $node): array return []; } - private function startsTaskListItem(ListItem $block): bool + private function needsBlockSeparator(?Node $child, bool $inTightList): bool { - $firstChild = $block->firstChild(); + if ($child instanceof Paragraph && $inTightList) { + return false; + } - return $firstChild instanceof Paragraph && $firstChild->firstChild() instanceof TaskListItemMarker; + return $child instanceof AbstractBlock; } } diff --git a/tests/functional/CMarkRegressionTest.php b/tests/functional/CMarkRegressionTest.php index 3ebd402fb..4a5d5f12d 100644 --- a/tests/functional/CMarkRegressionTest.php +++ b/tests/functional/CMarkRegressionTest.php @@ -27,12 +27,6 @@ public static function dataProvider(): \Generator { $tests = SpecReader::readFile(__DIR__ . '/../../vendor/commonmark/cmark/test/regression.txt'); foreach ($tests as $example) { - // We can't currently render spec example 13 exactly how the upstream library does. We'll likely need to overhaul - // our rendering approach in order to fix that, so we'll use this temporary workaround for now. - if ($example['number'] === 13) { - $example['output'] = \str_replace('', "\n", $example['output']); - } - // The case-fold test from example 21 fails on PHP 8.0.* and below due to the behavior of mb_convert_case(). // See https://3v4l.org/7TeXJ. if (\PHP_VERSION_ID < 81000 && $example['number'] === 21) { diff --git a/tests/functional/CommonMarkJSRegressionTest.php b/tests/functional/CommonMarkJSRegressionTest.php index 64cce7271..ce58efdde 100644 --- a/tests/functional/CommonMarkJSRegressionTest.php +++ b/tests/functional/CommonMarkJSRegressionTest.php @@ -25,17 +25,6 @@ final class CommonMarkJSRegressionTest extends AbstractSpecTestCase { public static function dataProvider(): \Generator { - $tests = SpecReader::readFile(__DIR__ . '/../../vendor/commonmark/commonmark.js/test/regression.txt'); - foreach ($tests as $example) { - // We can't currently render spec examples 18 or 24 exactly how the upstream library does. We'll likely need to overhaul - // our rendering approach in order to fix that, so we'll use this temporary workaround for now. - if ($example['number'] === 18) { - $example['output'] = \str_replace('', "\n", $example['output']); - } elseif ($example['number'] === 24) { - $example['output'] = \str_replace("
The following line is part of HTML block.\n\n", "
The following line is part of HTML block.\n", $example['output']);
-            }
-
-            yield $example;
-        }
+        yield from SpecReader::readFile(__DIR__ . '/../../vendor/commonmark/commonmark.js/test/regression.txt');
     }
 }
diff --git a/tests/functional/Extension/Autolink/UrlAutolinkParserTest.php b/tests/functional/Extension/Autolink/UrlAutolinkParserTest.php
index 8be6b9fac..e84cbd694 100644
--- a/tests/functional/Extension/Autolink/UrlAutolinkParserTest.php
+++ b/tests/functional/Extension/Autolink/UrlAutolinkParserTest.php
@@ -49,7 +49,7 @@ public static function dataProviderForAutolinkTests(): iterable
         yield ['www.google.com', '

www.google.com

']; yield [' http://leadingwhitespace.example.com', '

http://leadingwhitespace.example.com

']; yield ['http://trailingwhitespace.example.com ', '

http://trailingwhitespace.example.com

']; - yield ['- https://example.com/list-item', ""]; + yield ['- https://example.com/list-item', ""]; // Tests of "incomplete" URLs yield ['google.com is missing www and/or a protocol', '

google.com is missing www and/or a protocol

']; @@ -60,7 +60,7 @@ public static function dataProviderForAutolinkTests(): iterable yield ['Maybe you\'re interested in https://www.google.com/search?q=php+commonmark!', '

Maybe you\'re interested in https://www.google.com/search?q=php+commonmark!

']; yield ['Or perhaps you\'re looking for my personal website https://www.colinodell.com...?', '

Or perhaps you\'re looking for my personal website https://www.colinodell.com...?

']; yield ['Check https://www.stackoverflow.com: they have all the answers', '

Check https://www.stackoverflow.com: they have all the answers

']; - yield ['- https://example.com/list-item-with-trailing-colon:', ""]; + yield ['- https://example.com/list-item-with-trailing-colon:', ""]; yield ['Visit www.commonmark.org.', '

Visit www.commonmark.org.

']; yield ['Visit www.commonmark.org/a.b.', '

Visit www.commonmark.org/a.b.

']; diff --git a/tests/functional/Extension/Footnote/spec.txt b/tests/functional/Extension/Footnote/spec.txt index 63a090d0f..0ff84a81f 100644 --- a/tests/functional/Extension/Footnote/spec.txt +++ b/tests/functional/Extension/Footnote/spec.txt @@ -106,12 +106,9 @@ A [footnote identifier] can come immediately after a word, or have a space betwe [^5]: Not allowed .
    -
  • No spaces1 -
  • -
  • One space 2 -
  • -
  • Exclamation mark with space! 3 -
  • +
  • No spaces1
  • +
  • One space 2
  • +
  • Exclamation mark with space! 3
  • Exclamation mark with no space![^4]
  • Another exclamation mark![^5](not allowed)
diff --git a/tests/functional/Extension/TableOfContents/md/custom-class.html b/tests/functional/Extension/TableOfContents/md/custom-class.html index 9b3f5271d..84e70c9a8 100644 --- a/tests/functional/Extension/TableOfContents/md/custom-class.html +++ b/tests/functional/Extension/TableOfContents/md/custom-class.html @@ -1,10 +1,7 @@ diff --git a/tests/functional/Extension/TableOfContents/md/headings-with-inlines.html b/tests/functional/Extension/TableOfContents/md/headings-with-inlines.html index e89e44a15..aca203951 100644 --- a/tests/functional/Extension/TableOfContents/md/headings-with-inlines.html +++ b/tests/functional/Extension/TableOfContents/md/headings-with-inlines.html @@ -1,13 +1,7 @@

My Awesome Blog Post

This heading has a link

diff --git a/tests/functional/Extension/TableOfContents/md/html-in-headings.html b/tests/functional/Extension/TableOfContents/md/html-in-headings.html index 40c0b8a43..8e5bfe195 100644 --- a/tests/functional/Extension/TableOfContents/md/html-in-headings.html +++ b/tests/functional/Extension/TableOfContents/md/html-in-headings.html @@ -1,7 +1,5 @@

Here's a sample Markdown document

Hello World!

diff --git a/tests/functional/Extension/TableOfContents/md/min-max.html b/tests/functional/Extension/TableOfContents/md/min-max.html index a87d59025..bae12ce60 100644 --- a/tests/functional/Extension/TableOfContents/md/min-max.html +++ b/tests/functional/Extension/TableOfContents/md/min-max.html @@ -1,16 +1,11 @@