Test Failed
Push — feature-laravel-5.4 ( efd971...e8f7ac )
by Kirill
03:36
created

LaravelDocsRenderer::parseQuotes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 8
rs 9.4285
1
<?php
2
/**
3
 * This file is part of laravel.su package.
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
declare(strict_types=1);
8
9
namespace App\Services\ContentRenderer;
10
11
use cebe\markdown\Parser;
12
13
/**
14
 * Class LaravelDocsRenderer.
15
 */
16
class LaravelDocsRenderer extends MarkdownRenderer
17
{
18
    /**
19
     * LaravelDocsRenderer constructor.
20
     *
21
     * @param Parser $parser
22
     */
23
    public function __construct(Parser $parser)
24
    {
25
        parent::__construct($parser);
26
27
        // Remove unused content (headers and nav)
28
        $this->before($this->removeDocumentTitle());
29
        $this->before($this->removeLeadingNavigation());
30
31
32
        // Force hide anchors
33
        $this->before($this->hideExternalAnchors());
34
35
        // Cross-page navigation
36
        $this->before($this->fixDocsNavigationLinks());
37
38
        // Move "{tip}" and "{note}" to class
39
        $this->after($this->parseQuotes());
40
    }
41
42
    /**
43
     * Исправляет ссылки в документации "/docs/{version}/...".
44
     *
45
     * TODO Надо это не забыть реализовать =)
46
     *
47
     * @return \Closure
48
     */
49
    private function fixDocsNavigationLinks(): \Closure
50
    {
51
        return function (string $body) {
52
            return $body;
53
        };
54
    }
55
56
    /**
57
     * Заменяет все вхождения вида "> {tip}" на "<blockquote class="quote-tip">".
58
     *
59
     * @return \Closure
60
     */
61
    private function parseQuotes(): \Closure
62
    {
63
        $pattern = '/<blockquote>\s*<p>\s*{([a-z]+)}\s*(.*?)<\/p>\s*<\/blockquote>/isu';
64
65
        return function (string $body) use ($pattern) {
66
            return preg_replace($pattern, '<blockquote class="quote-$1">$2</blockquote>', $body);
67
        };
68
    }
69
70
    /**
71
     * Удаляет навигацию из начала документа.
72
     *
73
     * @return \Closure
74
     */
75
    private function removeLeadingNavigation(): \Closure
76
    {
77
        return function (string $body) {
78
            /**
79
             * TODO This expression are vulnerable: ReDoS-based exploit. Probably we can improve and fix it?
80
             *
81
             * @see https://en.wikipedia.org/wiki/ReDoS
82
             */
83
            return preg_replace('/^(?:[\n\s]*\-.*?\n)+/isu', '', $body);
84
        };
85
    }
86
87
    /**
88
     * Скрывает из исходного текста все вхождения "<a .... name="some">...</a>".
89
     * Требуется для избежания конфликтов с вёрсткой.
90
     *
91
     * @return \Closure
92
     */
93
    private function hideExternalAnchors(): \Closure
94
    {
95
        $replacement = '<a href="#" style="display: none;" name="$1"></a>';
96
97
        return function (string $body) use ($replacement) {
98
            return preg_replace('/<a.+?name="(.*?)".*?>.*?<\/a>/isu', $replacement, $body);
99
        };
100
    }
101
102
    /**
103
     * Удаляет из документа заголовки первого уровня, находящиеся в самом начале статьи.
104
     *
105
     * @return \Closure
106
     */
107
    private function removeDocumentTitle(): \Closure
108
    {
109
        return function (string $body) {
110
            return preg_replace('/^[\s\n]*?#\s+?.*?\n/isu', '', $body);
111
        };
112
    }
113
}
114