Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 42 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
RemexPipeline | |
0.00% |
0 / 42 |
|
0.00% |
0 / 6 |
72 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
12 | |||
insertUnfosteredMeta | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
insertImplicitStartTag | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
insertExplicitStartTag | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
insertExplicitEndTag | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
isFosterablePosition | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikimedia\Parsoid\Wt2Html\TreeBuilder; |
5 | |
6 | use Wikimedia\Parsoid\Config\Env; |
7 | use Wikimedia\Parsoid\Core\InternalException; |
8 | use Wikimedia\Parsoid\DOM\Document; |
9 | use Wikimedia\Parsoid\DOM\Element; |
10 | use Wikimedia\Parsoid\Wikitext\Consts; |
11 | use Wikimedia\RemexHtml\Tokenizer\PlainAttributes; |
12 | use Wikimedia\RemexHtml\Tokenizer\Tokenizer; |
13 | use Wikimedia\RemexHtml\TreeBuilder\Dispatcher; |
14 | use Wikimedia\RemexHtml\TreeBuilder\TreeBuilder; |
15 | use Wikimedia\RemexHtml\TreeBuilder\TreeMutationTracer; |
16 | |
17 | class RemexPipeline { |
18 | /** @var Dispatcher */ |
19 | public $dispatcher; |
20 | |
21 | /** @var TreeBuilder */ |
22 | public $treeBuilder; |
23 | |
24 | /** @var TreeMutationRelay */ |
25 | private $relay; |
26 | |
27 | /** @var DOMBuilder */ |
28 | public $domBuilder; |
29 | |
30 | /** @var Document */ |
31 | public $doc; |
32 | |
33 | private $nextFakeLength = 1; |
34 | |
35 | /** |
36 | * Create a RemexHtml pipeline |
37 | * |
38 | * Since we do our own tokenizing, the Dispatcher is called directly to push |
39 | * data into the pipeline. A RemexHtml Tokenizer is only needed to provide |
40 | * stub handling for certain TreeBuilder callbacks. Those callbacks are |
41 | * required by the HTML 5 spec -- we get away with ignoring them because |
42 | * we are not actually parsing HTML. |
43 | * |
44 | * @param Env $env |
45 | */ |
46 | public function __construct( Env $env ) { |
47 | $this->domBuilder = new DOMBuilder; |
48 | $this->relay = new TreeMutationRelay( $this->domBuilder ); |
49 | if ( $env->hasTraceFlag( 'remex' ) ) { |
50 | $tracer = new TreeMutationTracer( |
51 | $this->relay, |
52 | static function ( $msg ) use ( $env ) { |
53 | $env->log( 'trace/remex', $msg ); |
54 | } |
55 | ); |
56 | } else { |
57 | $tracer = $this->relay; |
58 | } |
59 | $this->treeBuilder = new TreeBuilder( $tracer ); |
60 | $this->dispatcher = new Dispatcher( $this->treeBuilder ); |
61 | |
62 | // Create dummy Tokenizer |
63 | $tokenizer = new Tokenizer( $this->dispatcher, '', [ 'ignoreErrors' => true ] ); |
64 | |
65 | $this->dispatcher->startDocument( $tokenizer, null, null ); |
66 | $this->dispatcher->doctype( 'html', '', '', false, 0, 0 ); |
67 | $this->dispatcher->startTag( 'body', new PlainAttributes(), false, 0, 0 ); |
68 | |
69 | $doc = $this->domBuilder->getFragment(); |
70 | if ( $doc instanceof Document ) { |
71 | $this->doc = $doc; |
72 | } else { |
73 | throw new InternalException( 'Invalid document type' ); |
74 | } |
75 | } |
76 | |
77 | /** |
78 | * Dispatch a meta tag in such a way that it won't be fostered even if the |
79 | * currently open element is a table. This replaces the old comment hack. |
80 | * |
81 | * @param array $attribs |
82 | */ |
83 | public function insertUnfosteredMeta( array $attribs ) { |
84 | $this->dispatcher->flushTableText(); |
85 | $this->dispatcher->inHead->startTag( |
86 | 'meta', |
87 | new Attributes( $this->doc, $attribs ), |
88 | false, 0, 0 |
89 | ); |
90 | } |
91 | |
92 | /** |
93 | * Dispatch a start tag and consider the generated element to be |
94 | * auto-inserted. |
95 | * |
96 | * @param string $name |
97 | * @param array $attribs |
98 | * @param bool $selfClose |
99 | */ |
100 | public function insertImplicitStartTag( |
101 | string $name, array $attribs, bool $selfClose = false |
102 | ): void { |
103 | $attribsObj = new Attributes( $this->doc, $attribs ); |
104 | $this->dispatcher->startTag( $name, $attribsObj, $selfClose, 0, 0 ); |
105 | } |
106 | |
107 | /** |
108 | * Dispatch a start tag and consider the generated element to be explicit, |
109 | * not auto-inserted. Return that element. If no element was created, |
110 | * return null. |
111 | * |
112 | * @param string $name |
113 | * @param array $attribs |
114 | * @param bool $selfClose |
115 | * @return Element|null |
116 | */ |
117 | public function insertExplicitStartTag( |
118 | string $name, array $attribs, bool $selfClose = false |
119 | ): ?Element { |
120 | $attribsObj = new Attributes( $this->doc, $attribs ); |
121 | $this->relay->matchStartTag( $attribsObj ); |
122 | $this->dispatcher->startTag( $name, $attribsObj, $selfClose, 0, 0 ); |
123 | $element = $this->relay->getMatchedElement(); |
124 | $this->relay->resetMatch(); |
125 | return $element; |
126 | } |
127 | |
128 | /** |
129 | * Dispatch an end tag, and cause the element to be explicitly ended, |
130 | * i.e. without autoInsertedEnd. Return the element which was ended by the |
131 | * tag, or null if no element was matched. |
132 | * |
133 | * @param string $name |
134 | * @param bool $isHTML |
135 | * @return Element|null |
136 | */ |
137 | public function insertExplicitEndTag( |
138 | string $name, bool $isHTML |
139 | ): ?Element { |
140 | $fakeLength = $this->nextFakeLength++; |
141 | $this->relay->matchEndTag( $fakeLength, $isHTML ); |
142 | $this->dispatcher->endTag( $name, 0, $fakeLength ); |
143 | $element = $this->relay->getMatchedElement(); |
144 | $this->relay->resetMatch(); |
145 | return $element; |
146 | } |
147 | |
148 | /** |
149 | * Determine if the TreeBuilder is in a fosterable position, i.e. insertion |
150 | * of a text node will cause fostering of that text. |
151 | * |
152 | * @return bool |
153 | */ |
154 | public function isFosterablePosition() { |
155 | $openElement = $this->treeBuilder->stack->current; |
156 | return isset( Consts::$HTML['FosterablePosition'][$openElement->htmlName] ); |
157 | } |
158 | |
159 | } |