Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 41 |
|
0.00% |
0 / 13 |
CRAP | |
0.00% |
0 / 1 |
DomSourceRange | |
0.00% |
0 / 41 |
|
0.00% |
0 / 13 |
420 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
innerSubstr | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
innerStart | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
innerEnd | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
innerLength | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
openSubstr | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
closeSubstr | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
stripTags | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
offset | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
hasValidTagWidths | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
20 | |||
fromTsr | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
fromArray | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
jsonSerialize | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikimedia\Parsoid\Core; |
5 | |
6 | use Wikimedia\Assert\Assert; |
7 | use Wikimedia\Parsoid\Tokens\SourceRange; |
8 | use Wikimedia\Parsoid\Utils\PHPUtils; |
9 | |
10 | /** |
11 | * Represents a DOM source range. That is, for a given DOM tree, gives |
12 | * the source offset range in the original wikitext for this DOM tree, |
13 | * as well as the opening and closing tag widths if appropriate. |
14 | */ |
15 | class DomSourceRange extends SourceRange { |
16 | /** |
17 | * Opening tag width. |
18 | * @var ?int |
19 | */ |
20 | public $openWidth; |
21 | |
22 | /** |
23 | * Closing tag width. |
24 | * @var ?int |
25 | */ |
26 | public $closeWidth; |
27 | |
28 | /** |
29 | * Width of trimmed whitespace between opening tag & first child. |
30 | * Defaults to zero since for most nodes, there is no ws trimming. |
31 | * -1 indicates that this information is invalid and should not be used. |
32 | * @var int |
33 | */ |
34 | public $leadingWS = 0; |
35 | |
36 | /** |
37 | * Width of trimmed whitespace between last child & closing tag. |
38 | * Defaults to zero since for most nodes, there is no ws trimming. |
39 | * -1 indicates that this information is invalid and should not be used. |
40 | * @var int |
41 | */ |
42 | public $trailingWS = 0; |
43 | |
44 | /** |
45 | * Create a new DOM source offset range (DSR). |
46 | * @param ?int $start The starting index (UTF-8 byte count, inclusive) |
47 | * @param ?int $end The ending index (UTF-8 byte count, exclusive) |
48 | * @param ?int $openWidth The width of the open container tag |
49 | * @param ?int $closeWidth The width of the close container tag |
50 | * @param int $leadingWS The width of WS chars between opening tag & first child |
51 | * @param int $trailingWS The width of WS chars between last child & closing tag |
52 | */ |
53 | public function __construct( |
54 | ?int $start, ?int $end, ?int $openWidth, ?int $closeWidth, |
55 | int $leadingWS = 0, |
56 | int $trailingWS = 0 |
57 | ) { |
58 | parent::__construct( $start, $end ); |
59 | $this->openWidth = $openWidth; |
60 | $this->closeWidth = $closeWidth; |
61 | $this->leadingWS = $leadingWS; |
62 | $this->trailingWS = $trailingWS; |
63 | } |
64 | |
65 | /** |
66 | * Return the substring of the given string corresponding to the |
67 | * inner portion of this range (that is, not including the opening |
68 | * and closing tag widths). |
69 | * @param string $str The source text string |
70 | * @return string |
71 | */ |
72 | public function innerSubstr( string $str ): string { |
73 | return PHPUtils::safeSubstr( $str, $this->innerStart(), $this->innerLength() ); |
74 | } |
75 | |
76 | /** |
77 | * Return the "inner start", that is, the start offset plus the open width. |
78 | * @return int |
79 | */ |
80 | public function innerStart(): int { |
81 | return $this->start + ( $this->openWidth ?? 0 ); |
82 | } |
83 | |
84 | /** |
85 | * Return the "inner end", that is, the end offset minus the close width. |
86 | * @return int |
87 | */ |
88 | public function innerEnd(): int { |
89 | return $this->end - ( $this->closeWidth ?? 0 ); |
90 | } |
91 | |
92 | /** |
93 | * Return the length of this source range, excluding the open and close |
94 | * tag widths. |
95 | * @return int |
96 | */ |
97 | public function innerLength(): int { |
98 | return $this->innerEnd() - $this->innerStart(); |
99 | } |
100 | |
101 | /** |
102 | * Return the substring of the given string corresponding to the |
103 | * open portion of this range. |
104 | * @param string $str The source text string |
105 | * @return string |
106 | */ |
107 | public function openSubstr( string $str ): string { |
108 | return PHPUtils::safeSubstr( $str, $this->start, $this->openWidth ); |
109 | } |
110 | |
111 | /** |
112 | * Return the substring of the given string corresponding to the |
113 | * close portion of this range. |
114 | * @param string $str The source text string |
115 | * @return string |
116 | */ |
117 | public function closeSubstr( string $str ): string { |
118 | return PHPUtils::safeSubstr( $str, $this->innerEnd(), $this->closeWidth ); |
119 | } |
120 | |
121 | /** |
122 | * Strip the tag open and close from the beginning and end of the |
123 | * provided string. This is similar to `DomSourceRange::innerSubstr()` |
124 | * but we assume that the string before `$this->start` and after |
125 | * `$this->end` has already been removed. (That is, that the input |
126 | * is `$this->substr( $originalWikitextSource )`.) |
127 | * |
128 | * @param string $src The source text string from `$this->start` |
129 | * (inclusive) to `$this->end` (exclusive). |
130 | * @return string |
131 | */ |
132 | public function stripTags( string $src ): string { |
133 | Assert::invariant( |
134 | strlen( $src ) === $this->length(), |
135 | "Input string not the expected length" |
136 | ); |
137 | return PHPUtils::safeSubstr( |
138 | $src, |
139 | $this->openWidth, |
140 | -$this->closeWidth |
141 | ); |
142 | } |
143 | |
144 | /** |
145 | * Return a new DOM source range shifted by $amount. |
146 | * @param int $amount The amount to shift by |
147 | * @return DomSourceRange |
148 | */ |
149 | public function offset( int $amount ): DomSourceRange { |
150 | return new DomSourceRange( |
151 | $this->start + $amount, |
152 | $this->end + $amount, |
153 | $this->openWidth, |
154 | $this->closeWidth, |
155 | $this->leadingWS, |
156 | $this->trailingWS |
157 | ); |
158 | } |
159 | |
160 | /** |
161 | * @return bool True if the tag widths are valid. |
162 | */ |
163 | public function hasValidTagWidths(): bool { |
164 | return $this->openWidth !== null && $this->closeWidth !== null && |
165 | $this->openWidth >= 0 && $this->closeWidth >= 0; |
166 | } |
167 | |
168 | /** |
169 | * Convert a TSR to a DSR with zero-width container open/close tags. |
170 | * @param SourceRange $tsr |
171 | * @return DomSourceRange |
172 | */ |
173 | public static function fromTsr( SourceRange $tsr ): DomSourceRange { |
174 | return new DomSourceRange( $tsr->start, $tsr->end, null, null ); |
175 | } |
176 | |
177 | /** |
178 | * Create a new DomSourceRange from an array of integers/null (such as |
179 | * created during JSON serialization). |
180 | * @param array<int|null> $dsr |
181 | * @return DomSourceRange |
182 | */ |
183 | public static function fromArray( array $dsr ): DomSourceRange { |
184 | $n = count( $dsr ); |
185 | Assert::invariant( $n === 2 || $n === 4 || $n === 6, 'Not enough elements in DSR array' ); |
186 | return new DomSourceRange( |
187 | $dsr[0], $dsr[1], $dsr[2] ?? null, $dsr[3] ?? null, $dsr[4] ?? 0, $dsr[5] ?? 0 |
188 | ); |
189 | } |
190 | |
191 | /** |
192 | * @inheritDoc |
193 | */ |
194 | public function jsonSerialize(): array { |
195 | $a = [ $this->start, $this->end, $this->openWidth, $this->closeWidth ]; |
196 | if ( $this->leadingWS !== 0 || $this->trailingWS !== 0 ) { |
197 | $a[] = $this->leadingWS; |
198 | $a[] = $this->trailingWS; |
199 | } |
200 | return $a; |
201 | } |
202 | } |