1<?php
2
3/*
4 * This file is part of the league/commonmark package.
5 *
6 * (c) Colin O'Dell <colinodell@gmail.com>
7 *
8 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
9 *  - (c) John MacFarlane
10 *
11 * For the full copyright and license information, please view the LICENSE
12 * file that was distributed with this source code.
13 */
14
15namespace League\CommonMark;
16
17use League\CommonMark\Block\Element\AbstractBlock;
18use League\CommonMark\Block\Renderer\BlockRendererInterface;
19use League\CommonMark\Inline\Element\AbstractInline;
20use League\CommonMark\Inline\Renderer\InlineRendererInterface;
21
22/**
23 * Renders a parsed AST to HTML
24 */
25final class HtmlRenderer implements ElementRendererInterface
26{
27    /**
28     * @var EnvironmentInterface
29     */
30    protected $environment;
31
32    /**
33     * @param EnvironmentInterface $environment
34     */
35    public function __construct(EnvironmentInterface $environment)
36    {
37        $this->environment = $environment;
38    }
39
40    /**
41     * @param string $option
42     * @param mixed  $default
43     *
44     * @return mixed|null
45     */
46    public function getOption(string $option, $default = null)
47    {
48        return $this->environment->getConfig('renderer/' . $option, $default);
49    }
50
51    /**
52     * @param AbstractInline $inline
53     *
54     * @throws \RuntimeException
55     *
56     * @return string
57     */
58    public function renderInline(AbstractInline $inline): string
59    {
60        $renderers = $this->environment->getInlineRenderersForClass(\get_class($inline));
61
62        /** @var InlineRendererInterface $renderer */
63        foreach ($renderers as $renderer) {
64            if (($result = $renderer->render($inline, $this)) !== null) {
65                return $result;
66            }
67        }
68
69        throw new \RuntimeException('Unable to find corresponding renderer for inline type ' . \get_class($inline));
70    }
71
72    /**
73     * @param AbstractInline[] $inlines
74     *
75     * @return string
76     */
77    public function renderInlines(iterable $inlines): string
78    {
79        $result = [];
80        foreach ($inlines as $inline) {
81            $result[] = $this->renderInline($inline);
82        }
83
84        return \implode('', $result);
85    }
86
87    /**
88     * @param AbstractBlock $block
89     * @param bool          $inTightList
90     *
91     * @throws \RuntimeException
92     *
93     * @return string
94     */
95    public function renderBlock(AbstractBlock $block, bool $inTightList = false): string
96    {
97        $renderers = $this->environment->getBlockRenderersForClass(\get_class($block));
98
99        /** @var BlockRendererInterface $renderer */
100        foreach ($renderers as $renderer) {
101            if (($result = $renderer->render($block, $this, $inTightList)) !== null) {
102                return $result;
103            }
104        }
105
106        throw new \RuntimeException('Unable to find corresponding renderer for block type ' . \get_class($block));
107    }
108
109    /**
110     * @param AbstractBlock[] $blocks
111     * @param bool            $inTightList
112     *
113     * @return string
114     */
115    public function renderBlocks(iterable $blocks, bool $inTightList = false): string
116    {
117        $result = [];
118        foreach ($blocks as $block) {
119            $result[] = $this->renderBlock($block, $inTightList);
120        }
121
122        $separator = $this->getOption('block_separator', "\n");
123
124        return \implode($separator, $result);
125    }
126}
127