Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.82% covered (success)
95.82%
275 / 287
50.00% covered (danger)
50.00%
5 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
BlockLevelPass
96.15% covered (success)
96.15%
275 / 286
50.00% covered (danger)
50.00%
5 / 10
119
0.00% covered (danger)
0.00%
0 / 1
 doBlockLevels
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 hasOpenParagraph
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 closeParagraph
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 getCommon
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 openList
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
5.01
 nextItem
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
7.03
 closeList
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
5.02
 execute
97.04% covered (success)
97.04%
131 / 135
0.00% covered (danger)
0.00%
0 / 1
54
 findColonNoLinks
95.92% covered (success)
95.92%
94 / 98
0.00% covered (danger)
0.00%
0 / 1
39
1<?php
2
3/**
4 * This is the part of the wikitext parser which handles automatic paragraphs
5 * and conversion of start-of-line prefixes to HTML lists.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * http://www.gnu.org/copyleft/gpl.html
21 *
22 * @file
23 * @ingroup Parser
24 * @internal
25 */
26
27namespace MediaWiki\Parser;
28
29use LogicException;
30use StringUtils;
31
32class BlockLevelPass {
33    /** @var bool */
34    private $DTopen = false;
35    /** @var bool */
36    private $inPre = false;
37    /** @var string */
38    private $lastParagraph = '';
39    /** @var bool */
40    private $lineStart;
41    /** @var string */
42    private $text;
43
44    # State constants for the definition list colon extraction
45    private const COLON_STATE_TEXT = 0;
46    private const COLON_STATE_TAG = 1;
47    private const COLON_STATE_TAGSTART = 2;
48    private const COLON_STATE_CLOSETAG = 3;
49    private const COLON_STATE_TAGSLASH = 4;
50    private const COLON_STATE_COMMENT = 5;
51    private const COLON_STATE_COMMENTDASH = 6;
52    private const COLON_STATE_COMMENTDASHDASH = 7;
53    private const COLON_STATE_LC = 8;
54
55    /**
56     * Make lists from lines starting with ':', '*', '#', etc.
57     *
58     * @param string $text
59     * @param bool $lineStart Whether or not this is at the start of a line.
60     * @return string The lists rendered as HTML
61     * @internal
62     */
63    public static function doBlockLevels( $text, $lineStart ) {
64        $pass = new self( $text, $lineStart );
65        return $pass->execute();
66    }
67
68    /**
69     * @param string $text
70     * @param bool $lineStart
71     */
72    private function __construct( $text, $lineStart ) {
73        $this->text = $text;
74        $this->lineStart = $lineStart;
75    }
76
77    /**
78     * @return bool
79     */
80    private function hasOpenParagraph() {
81        return $this->lastParagraph !== '';
82    }
83
84    /**
85     * If a pre or p is open, return the corresponding close tag and update
86     * the state. If no tag is open, return an empty string.
87     * @param bool $atTheEnd Omit trailing newline if we've reached the end.
88     * @return string
89     */
90    private function closeParagraph( $atTheEnd = false ) {
91        $result = '';
92        if ( $this->hasOpenParagraph() ) {
93            $result = '</' . $this->lastParagraph . '>';
94            if ( !$atTheEnd ) {
95                $result .= "\n";
96            }
97        }
98        $this->inPre = false;
99        $this->lastParagraph = '';
100        return $result;
101    }
102
103    /**
104     * getCommon() returns the length of the longest common substring
105     * of both arguments, starting at the beginning of both.
106     *
107     * @param string $st1
108     * @param string $st2
109     *
110     * @return int
111     */
112    private function getCommon( $st1, $st2 ) {
113        $shorter = min( strlen( $st1 ), strlen( $st2 ) );
114
115        for ( $i = 0; $i < $shorter; ++$i ) {
116            if ( $st1[$i] !== $st2[$i] ) {
117                break;
118            }
119        }
120        return $i;
121    }
122
123    /**
124     * Open the list item element identified by the prefix character.
125     *
126     * @param string $char
127     *
128     * @return string
129     */
130    private function openList( $char ) {
131        $result = $this->closeParagraph();
132
133        if ( $char === '*' ) {
134            $result .= "<ul><li>";
135        } elseif ( $char === '#' ) {
136            $result .= "<ol><li>";
137        } elseif ( $char === ':' ) {
138            $result .= "<dl><dd>";
139        } elseif ( $char === ';' ) {
140            $result .= "<dl><dt>";
141            $this->DTopen = true;
142        } else {
143            $result = '<!-- ERR 1 -->';
144        }
145
146        return $result;
147    }
148
149    /**
150     * Close the current list item and open the next one.
151     * @param string $char
152     *
153     * @return string
154     */
155    private function nextItem( $char ) {
156        if ( $char === '*' || $char === '#' ) {
157            return "</li>\n<li>";
158        } elseif ( $char === ':' || $char === ';' ) {
159            $close = "</dd>\n";
160            if ( $this->DTopen ) {
161                $close = "</dt>\n";
162            }
163            if ( $char === ';' ) {
164                $this->DTopen = true;
165                return $close . '<dt>';
166            } else {
167                $this->DTopen = false;
168                return $close . '<dd>';
169            }
170        }
171        return '<!-- ERR 2 -->';
172    }
173
174    /**
175     * Close the current list item identified by the prefix character.
176     * @param string $char
177     *
178     * @return string
179     */
180    private function closeList( $char ) {
181        if ( $char === '*' ) {
182            $text = "</li></ul>";
183        } elseif ( $char === '#' ) {
184            $text = "</li></ol>";
185        } elseif ( $char === ':' ) {
186            if ( $this->DTopen ) {
187                $this->DTopen = false;
188                $text = "</dt></dl>";
189            } else {
190                $text = "</dd></dl>";
191            }
192        } else {
193            return '<!-- ERR 3 -->';
194        }
195        return $text;
196    }
197
198    /**
199     * Execute the pass.
200     * @return string
201     */
202    private function execute() {