Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 50 |
|
0.00% |
0 / 20 |
CRAP | |
0.00% |
0 / 1 |
DomSourceRange | |
0.00% |
0 / 50 |
|
0.00% |
0 / 20 |
870 | |
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 | |||
openRange | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
closeRange | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
innerRange | |
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 | |||
hasTrimmedWS | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
hasValidLeadingWS | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
hasValidTrailingWS | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
fromTsr | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
newFromJsonArray | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
toJsonArray | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
hint | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikimedia\Parsoid\Core; |
5 | |
6 | use Wikimedia\Assert\Assert; |
7 | use Wikimedia\JsonCodec\Hint; |
8 | use Wikimedia\Parsoid\Tokens\SourceRange; |
9 | use Wikimedia\Parsoid\Utils\PHPUtils; |
10 | |
11 | /** |
12 | * Represents a DOM source range. That is, for a given DOM tree, gives |
13 | * the source offset range in the original wikitext for this DOM tree, |
14 | * as well as the opening and closing tag widths if appropriate. |
15 | */ |
16 | class DomSourceRange extends SourceRange { |
17 | /** |
18 | * Opening tag width. |
19 | * @var ?int |
20 | */ |
21 | public $openWidth; |
22 | |
23 | /** |
24 | * Closing tag width. |
25 | * @var ?int |
26 | */ |
27 | public $closeWidth; |
28 | |
29 | /** |
30 | * Width of trimmed whitespace between opening tag & first child. |
31 | * Defaults to zero since for most nodes, there is no ws trimming. |
32 | * -1 indicates that this information is invalid and should not be used. |
33 | * @var int |
34 | */ |
35 | public $leadingWS = 0; |
36 | |
37 | /** |
38 | * Width of trimmed whitespace between last child & closing tag. |
39 | * Defaults to zero since for most nodes, there is no ws trimming. |
40 | * -1 indicates that this information is invalid and should not be used. |
41 | * @var int |
42 | */ |
43 | public $trailingWS = 0; |
44 | |
45 | /** |
46 | * Create a new DOM source offset range (DSR). |
47 | * @param ?int $start The starting index (UTF-8 byte count, inclusive) |
48 | * @param ?int $end The ending index (UTF-8 byte count, exclusive) |
49 | * @param ?int $openWidth The width of the open container tag |
50 | * @param ?int $closeWidth The width of the close container tag |
51 | * @param int $leadingWS The width of WS chars between opening tag & first child |
52 | * @param int $trailingWS The width of WS chars between last child & closing tag |
53 | */ |
54 | public function __construct( |
55 | ?int $start, ?int $end, ?int $openWidth, ?int $closeWidth, |
56 | int $leadingWS = 0, |
57 | int $trailingWS = 0 |
58 | ) { |
59 | parent::__construct( $start, $end ); |
60 | $this->openWidth = $openWidth; |
61 | $this->closeWidth = $closeWidth; |
62 | $this->leadingWS = $leadingWS; |
63 | $this->trailingWS = $trailingWS; |
64 | } |
65 | |
66 | /** |
67 | * Return the substring of the given string corresponding to the |
68 | * inner portion of this range (that is, not including the opening |
69 | * and closing tag widths). |
70 | * @param string $str The source text string |
71 | * @return string |
72 | */ |
73 | public function innerSubstr( string $str ): string { |
74 | return PHPUtils::safeSubstr( $str, $this->innerStart(), $this->innerLength() ); |
75 | } |
76 | |
77 | /** |
78 | * Return the "inner start", that is, the start offset plus the open width. |
79 | * @return int |
80 | */ |
81 | public function innerStart(): int { |
82 | return $this->start + ( $this->openWidth ?? 0 ); |
83 | } |
84 | |
85 | /** |
86 | * Return the "inner end", that is, the end offset minus the close width. |
87 | * @return int |
88 | */ |
89 | public function innerEnd(): int { |
90 | return $this->end - ( $this->closeWidth ?? 0 ); |
91 | } |
92 | |
93 | /** |
94 | * Return the length of this source range, excluding the open and close |
95 | * tag widths. |
96 | * @return int |
97 | */ |
98 | public function innerLength(): int { |
99 | return $this->innerEnd() - $this->innerStart(); |
100 | } |
101 | |
102 | /** |
103 | * Return the substring of the given string corresponding to the |
104 | * open portion of this range. |
105 | * @param string $str The source text string |
106 | * @return string |
107 | */ |
108 | public function openSubstr( string $str ): string { |
109 | return PHPUtils::safeSubstr( $str, $this->start, $this->openWidth ); |
110 | } |
111 | |
112 | /** |
113 | * Return the substring of the given string corresponding to the |
114 | * close portion of this range. |
115 | * @param string $str The source text string |
116 | * @return string |
117 | */ |
118 | public function closeSubstr( string $str ): string { |
119 | return PHPUtils::safeSubstr( $str, $this->innerEnd(), $this->closeWidth ); |
120 | } |
121 | |
122 | /** |
123 | * Return the source range corresponding to the open portion of this range. |
124 | * @return SourceRange |
125 | */ |
126 | public function openRange(): SourceRange { |
127 | return new SourceRange( $this->start, $this->innerStart() ); |
128 | } |
129 | |
130 | /** |
131 | * Return the source range corresponding to the close portion of this range. |
132 | * @return SourceRange |
133 | */ |
134 | public function closeRange(): SourceRange { |
135 | return new SourceRange( $this->innerEnd(), $this->end ); |
136 | } |
137 | |
138 | /** |
139 | * Return the source range corresponding to the inner portion of this range. |
140 | * @return SourceRange |
141 | */ |
142 | public function innerRange(): SourceRange { |
143 | return new SourceRange( $this->innerStart(), $this->innerEnd() ); |
144 | } |
145 | |
146 | /** |
147 | * Strip the tag open and close from the beginning and end of the |
148 | * provided string. This is similar to `DomSourceRange::innerSubstr()` |
149 | * but we assume that the string before `$this->start` and after |
150 | * `$this->end` has already been removed. (That is, that the input |
151 | * is `$this->substr( $originalWikitextSource )`.) |
152 | * |
153 | * @param string $src The source text string from `$this->start` |
154 | * (inclusive) to `$this->end` (exclusive). |
155 | * @return string |
156 | */ |
157 | public function stripTags( string $src ): string { |
158 | Assert::invariant( |
159 | strlen( $src ) === $this->length(), |
160 | "Input string not the expected length" |
161 | ); |
162 | return PHPUtils::safeSubstr( |
163 | $src, |
164 | $this->openWidth, |
165 | -$this->closeWidth |
166 | ); |
167 | } |
168 | |
169 | /** |
170 | * Return a new DOM source range shifted by $amount. |
171 | * @param int $amount The amount to shift by |
172 | * @return DomSourceRange |
173 | */ |
174 | public function offset( int $amount ): DomSourceRange { |
175 | return new DomSourceRange( |
176 | $this->start + $amount, |
177 | $this->end + $amount, |
178 | $this->openWidth, |
179 | $this->closeWidth, |
180 | $this->leadingWS, |
181 | $this->trailingWS |
182 | ); |
183 | } |
184 | |
185 | /** |
186 | * @return bool True if the tag widths are valid. |
187 | */ |
188 | public function hasValidTagWidths(): bool { |
189 | return $this->openWidth !== null && $this->closeWidth !== null && |
190 | $this->openWidth >= 0 && $this->closeWidth >= 0; |
191 | } |
192 | |
193 | /** |
194 | * Determine if this DSR records that whitespace was trimmed from |
195 | * this node. Note that this doesn't mean that the amount trimmed |
196 | * is known; use ::hasValidLeadingWS() or ::hasValidTrimmedWS() |
197 | * to determine that. |
198 | * @return bool True if either leadingWS or trailingWS is non-zero. |
199 | */ |
200 | public function hasTrimmedWS(): bool { |
201 | return $this->leadingWS !== 0 || $this->trailingWS !== 0; |
202 | } |
203 | |
204 | /** |
205 | * @note In most cases you should check to see if this node |
206 | * ::hasTrimmedWS() *and* whether the amount is valid. |
207 | * @return bool if the amount of leading whitespace is known. |
208 | */ |
209 | public function hasValidLeadingWS(): bool { |
210 | return $this->leadingWS !== -1; |
211 | } |
212 | |
213 | /** |
214 | * @note In most cases you should check to see if this node |
215 | * ::hasTrimmedWS() *and* whether the amount is valid. |
216 | * @return bool if the amount of trailing whitespace is known. |
217 | */ |
218 | public function hasValidTrailingWS(): bool { |
219 | return $this->trailingWS !== -1; |
220 | } |
221 | |
222 | /** |
223 | * Convert a TSR to a DSR with zero-width container open/close tags. |
224 | * @param SourceRange $tsr |
225 | * @return DomSourceRange |
226 | */ |
227 | public static function fromTsr( SourceRange $tsr ): DomSourceRange { |
228 | if ( $tsr instanceof DomSourceRange ) { |
229 | return $tsr; |
230 | } |
231 | return new DomSourceRange( $tsr->start, $tsr->end, null, null ); |
232 | } |
233 | |
234 | /** |
235 | * Create a new DomSourceRange from an array of integers/null (such as |
236 | * created during JSON serialization). |
237 | * @param array<int|null> $dsr |
238 | * @return DomSourceRange |
239 | */ |
240 | public static function newFromJsonArray( array $dsr ): DomSourceRange { |
241 | $n = count( $dsr ); |
242 | Assert::invariant( $n === 2 || $n === 4 || $n === 6, 'Not enough elements in DSR array' ); |
243 | return new DomSourceRange( |
244 | $dsr[0], $dsr[1], $dsr[2] ?? null, $dsr[3] ?? null, $dsr[4] ?? 0, $dsr[5] ?? 0 |
245 | ); |
246 | } |
247 | |
248 | /** |
249 | * @inheritDoc |
250 | */ |
251 | public function toJsonArray(): array { |
252 | $a = [ $this->start, $this->end, $this->openWidth, $this->closeWidth ]; |
253 | if ( $this->leadingWS !== 0 || $this->trailingWS !== 0 ) { |
254 | $a[] = $this->leadingWS; |
255 | $a[] = $this->trailingWS; |
256 | } |
257 | return $a; |
258 | } |
259 | |
260 | /** JsonCodec serialization hint. */ |
261 | public static function hint(): Hint { |
262 | return Hint::build( self::class, Hint::USE_SQUARE ); |
263 | } |
264 | } |