Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 66 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
PageBundle | |
0.00% |
0 / 66 |
|
0.00% |
0 / 7 |
342 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
toDom | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
toHtml | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
validate | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
42 | |||
responseData | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
6 | |||
apply | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
42 | |||
encodeForHeadElement | |
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 Composer\Semver\Semver; |
7 | use Wikimedia\Parsoid\DOM\Document; |
8 | use Wikimedia\Parsoid\DOM\Element; |
9 | use Wikimedia\Parsoid\DOM\Node; |
10 | use Wikimedia\Parsoid\Utils\ContentUtils; |
11 | use Wikimedia\Parsoid\Utils\DOMCompat; |
12 | use Wikimedia\Parsoid\Utils\DOMDataUtils; |
13 | use Wikimedia\Parsoid\Utils\DOMUtils; |
14 | use Wikimedia\Parsoid\Utils\PHPUtils; |
15 | |
16 | /** |
17 | * PORT-FIXME: This is just a placeholder for data that was previously passed |
18 | * to entrypoint in JavaScript. Who will construct these objects and whether |
19 | * this is the correct interface is yet to be determined. |
20 | */ |
21 | class PageBundle { |
22 | /** @var string */ |
23 | public $html; |
24 | |
25 | /** @var ?array */ |
26 | public $parsoid; |
27 | |
28 | /** @var ?array */ |
29 | public $mw; |
30 | |
31 | /** @var ?string */ |
32 | public $version; |
33 | |
34 | /** @var ?array */ |
35 | public $headers; |
36 | |
37 | /** @var string|null */ |
38 | public $contentmodel; |
39 | |
40 | public function __construct( |
41 | string $html, ?array $parsoid = null, ?array $mw = null, |
42 | ?string $version = null, ?array $headers = null, |
43 | ?string $contentmodel = null |
44 | ) { |
45 | $this->html = $html; |
46 | $this->parsoid = $parsoid; |
47 | $this->mw = $mw; |
48 | $this->version = $version; |
49 | $this->headers = $headers; |
50 | $this->contentmodel = $contentmodel; |
51 | } |
52 | |
53 | public function toDom(): Document { |
54 | $doc = DOMUtils::parseHTML( $this->html ); |
55 | self::apply( $doc, $this ); |
56 | return $doc; |
57 | } |
58 | |
59 | public function toHtml(): string { |
60 | return ContentUtils::toXML( $this->toDom() ); |
61 | } |
62 | |
63 | /** |
64 | * Check if this pagebundle is valid. |
65 | * @param string $contentVersion Document content version to validate against. |
66 | * @param ?string &$errorMessage Error message will be returned here. |
67 | * @return bool |
68 | */ |
69 | public function validate( |
70 | string $contentVersion, ?string &$errorMessage = null |
71 | ) { |
72 | if ( !$this->parsoid || !isset( $this->parsoid['ids'] ) ) { |
73 | $errorMessage = 'Invalid data-parsoid was provided.'; |
74 | return false; |
75 | } elseif ( Semver::satisfies( $contentVersion, '^999.0.0' ) |
76 | && ( !$this->mw || !isset( $this->mw['ids'] ) ) |
77 | ) { |
78 | $errorMessage = 'Invalid data-mw was provided.'; |
79 | return false; |
80 | } |
81 | return true; |
82 | } |
83 | |
84 | /** |
85 | * @return array |
86 | */ |
87 | public function responseData() { |
88 | $responseData = [ |
89 | 'contentmodel' => $this->contentmodel ?? '', |
90 | 'html' => [ |
91 | 'headers' => array_merge( [ |
92 | 'content-type' => 'text/html; charset=utf-8; ' |
93 | . 'profile="https://www.mediawiki.org/wiki/Specs/HTML/' |
94 | . $this->version . '"', |
95 | ], $this->headers ?? [] ), |
96 | 'body' => $this->html, |
97 | ], |
98 | 'data-parsoid' => [ |
99 | 'headers' => [ |
100 | 'content-type' => 'application/json; charset=utf-8; ' |
101 | . 'profile="https://www.mediawiki.org/wiki/Specs/data-parsoid/' |
102 | . $this->version . '"', |
103 | ], |
104 | 'body' => $this->parsoid, |
105 | ], |
106 | ]; |
107 | if ( Semver::satisfies( $this->version, '^999.0.0' ) ) { |
108 | $responseData['data-mw'] = [ |
109 | 'headers' => [ |
110 | 'content-type' => 'application/json; charset=utf-8; ' . |
111 | 'profile="https://www.mediawiki.org/wiki/Specs/data-mw/' . |
112 | $this->version . '"', |
113 | ], |
114 | 'body' => $this->mw, |
115 | ]; |
116 | } |
117 | return $responseData; |
118 | } |
119 | |
120 | /** |
121 | * Applies the `data-*` attributes JSON structure to the document. |
122 | * Leaves `id` attributes behind -- they are used by citation code to |
123 | * extract `<ref>` body from the DOM. |
124 | * |
125 | * @param Document $doc doc |
126 | * @param PageBundle $pb page bundle |
127 | */ |
128 | public static function apply( Document $doc, PageBundle $pb ): void { |
129 | DOMUtils::visitDOM( |
130 | DOMCompat::getBody( $doc ), |
131 | static function ( Node $node ) use ( &$pb ): void { |
132 | if ( $node instanceof Element ) { |
133 | $id = DOMCompat::getAttribute( $node, 'id' ); |
134 | if ( $id === null ) { |
135 | return; |
136 | } |
137 | if ( isset( $pb->parsoid['ids'][$id] ) ) { |
138 | DOMDataUtils::setJSONAttribute( |
139 | $node, 'data-parsoid', $pb->parsoid['ids'][$id] |
140 | ); |
141 | } |
142 | if ( isset( $pb->mw['ids'][$id] ) ) { |
143 | // Only apply if it isn't already set. This means |
144 | // earlier applications of the pagebundle have higher |
145 | // precedence, inline data being the highest. |
146 | if ( !$node->hasAttribute( 'data-mw' ) ) { |
147 | DOMDataUtils::setJSONAttribute( |
148 | $node, 'data-mw', $pb->mw['ids'][$id] |
149 | ); |
150 | } |
151 | } |
152 | } |
153 | } |
154 | ); |
155 | } |
156 | |
157 | /** |
158 | * Encode some of these properties for emitting in the <heaad> element of a doc |
159 | * @return string |
160 | */ |
161 | public function encodeForHeadElement(): string { |
162 | return PHPUtils::jsonEncode( [ 'parsoid' => $this->parsoid ?? [], 'mw' => $this->mw ?? [] ] ); |
163 | } |
164 | } |