1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Libraries\Markdown\Indexing\Renderers;
7
8use League\CommonMark\Node\Block\AbstractBlock;
9use League\CommonMark\Node\Block\TightBlockInterface;
10use League\CommonMark\Node\Node;
11use League\CommonMark\Renderer\ChildNodeRendererInterface;
12use League\CommonMark\Renderer\NodeRendererInterface;
13
14class BlockRenderer implements NodeRendererInterface
15{
16 /**
17 * Finds the enclosing parent level block element for a given node.
18 *
19 * @param Node $node
20 * @return AbstractBlock|null
21 */
22 public static function getEnclosingBlock(Node $node): ?AbstractBlock
23 {
24 $parent = $node->parent();
25 if ($parent instanceof AbstractBlock) {
26 return $parent;
27 } elseif ($parent instanceof Node) {
28 return static::getEnclosingBlock($parent);
29 }
30
31 return null;
32 }
33
34 public function render(Node $node, ChildNodeRendererInterface $childRenderer): string
35 {
36 $rendered = [];
37
38 $children = $node->children();
39 foreach ($children as $child) {
40 $rendered[] = $childRenderer->renderNodes([$child]);
41 }
42
43 $text = implode('', $rendered);
44 // check if this block will effectively be empty.
45 if (!present(trim($text))) {
46 return '';
47 }
48
49 return static::inTightList($node) ? $text : $text."\n";
50 }
51
52 private static function inTightList(Node $node): bool
53 {
54 $parent = $node->parent();
55 if ($parent instanceof TightBlockInterface) {
56 return $parent->isTight();
57 }
58
59 return false;
60 }
61}