Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ParserHook
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 4
702
0.00% covered (danger)
0.00%
0 / 1
 sourceToDom
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 1
240
 processAttributeEmbeddedDom
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 domToWikitext
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
56
 getConfig
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace Wikimedia\Parsoid\ParserTests;
5
6use Error;
7use Wikimedia\Parsoid\DOM\DocumentFragment;
8use Wikimedia\Parsoid\DOM\Element;
9use Wikimedia\Parsoid\Ext\ExtensionModule;
10use Wikimedia\Parsoid\Ext\ExtensionTagHandler;
11use Wikimedia\Parsoid\Ext\ParsoidExtensionAPI;
12use Wikimedia\Parsoid\Utils\DOMCompat;
13use Wikimedia\Parsoid\Utils\DOMDataUtils;
14use Wikimedia\Parsoid\Utils\WTUtils;
15
16/**
17 * See tests/parser/ParserTestParserHook.php in core.
18 */
19class ParserHook extends ExtensionTagHandler implements ExtensionModule {
20
21    /** @inheritDoc */
22    public function sourceToDom(
23        ParsoidExtensionAPI $extApi, string $content, array $args
24    ): DocumentFragment {
25        $extName = $extApi->extTag->getName();
26        if ( $extApi->extTag->isSelfClosed() ) {
27            $content = null;
28        }
29        switch ( $extName ) {
30            case 'tag':
31            case 'tåg':
32                return $extApi->htmlToDom(
33                    "<pre>\n" .
34                        var_export( $content, true ) . "\n" .
35                        var_export( $extApi->extArgsToArray( $args ), true ) . "\n" .
36                    "</pre>"
37                );
38
39            case 'statictag':
40                // FIXME: Choose a better DOM representation that doesn't mess with
41                // newline constraints.
42                return $extApi->htmlToDom( '<span />' );
43
44            case 'asidetag':
45                // T278565
46                return $extApi->htmlToDom( '<aside>Some aside content</aside>' );
47
48            case 'pwraptest':
49                return $extApi->htmlToDom( '<!--CMT--><style>p{}</style>' );
50
51            case 'divtag':
52            case 'spantag':
53                // "Transparent" tag which wraps wikitext in a <span> or <div>;
54                // useful in testing various parsoid wrapping scenarios
55                // (we used to use <ref> for this)
56                //
57                // NOTE: When using <spantag>, p-wrapping and indent-pre
58                // transforms are disabled.
59                $argArray = $extApi->extArgsToArray( $args );
60                $isDiv = ( $extName === 'divtag' );
61                $isRaw = $argArray['raw'] ?? false;
62                $tag = $isDiv ? 'div' : 'span';
63                if ( $isRaw ) {
64                    return $extApi->htmlToDom( "<$tag>$content</$tag>" );
65                }
66                return $extApi->extTagToDOM( $args, $content, [
67                    'wrapperTag' => $tag,
68                    'parseOpts' => [
69                        'extTag' => $extName,
70                        'context' => $isDiv ? 'block' : 'inline',
71                    ],
72                ] );
73
74            case 'embedtag':
75                $dataMw = $extApi->extTag->getDefaultDataMw();
76                $domFragment = $extApi->extTagToDOM( $args, $content, [
77                    'parseOpts' => [
78                        'extTag' => $extName,
79                        'context' => 'inline',
80                    ],
81                ] );
82                $dataMw->body = (object)[
83                    'html' => $extApi->domToHtml( $domFragment, true )
84                ];
85                $span = $domFragment->ownerDocument->createElement( 'span' );
86                DOMDataUtils::setDataMw( $span, $dataMw );
87                DOMCompat::replaceChildren( $domFragment, $span );
88                return $domFragment;
89
90            case 'sealtag':
91                return $extApi->htmlToDom( '<span />' );
92
93            default:
94                throw new Error( "Unexpected tag name: $extName in ParserHook" );
95        }
96    }
97
98    /** @inheritDoc */
99    public function processAttributeEmbeddedDom(
100        ParsoidExtensionAPI $extApi, Element $elt, callable $proc
101    ): void {
102        $dataMw = DOMDataUtils::getDataMw( $elt );
103        if ( isset( $dataMw->body->html ) ) {
104            $dom = $extApi->htmlToDom( $dataMw->body->html );
105            $ret = $proc( $dom );
106            if ( $ret ) {
107                $dataMw->body->html = $extApi->domToHtml( $dom, true, true );
108            }
109        }
110    }
111
112    /** @inheritDoc */
113    public function domToWikitext(
114        ParsoidExtensionAPI $extApi, Element $node, bool $wrapperUnmodified
115    ) {
116        $dataMw = DOMDataUtils::getDataMw( $node );
117        $extName = WTUtils::getExtTagName( $node ) ?? $dataMw->name;
118        if ( !in_array( $extName, [ 'spantag', 'divtag', 'embedtag' ], true ) ) {
119            return false; // use default serialization
120        }
121        if ( in_array( $extName, [ 'spantag', 'divtag' ], true ) ) {
122            if ( $dataMw->attrs->raw ?? false ) {
123                return false; // use default serialization in 'raw' mode
124            }
125        }
126        $html2wtOpts = [
127            'extName' => $extName,
128            // FIXME: One-off PHP parser state leak. This needs a better solution.
129            'inPHPBlock' => true
130        ];
131        $src = '';
132        if ( $wrapperUnmodified && isset( $dataMw->body->extsrc ) ) {
133            $src = $dataMw->body->extsrc;
134        } elseif ( $extName === 'embedtag' ) {
135            // First look for the extension's content in data-mw.body.html
136            $src = $extApi->htmlToWikitext( $html2wtOpts, $dataMw->body->html );
137        } else {
138            $src = $extApi->htmlToWikitext( $html2wtOpts, DOMCompat::getInnerHTML( $node ) );
139        }
140        return "<$extName>" . $src . "</$extName>";
141    }
142
143    /** @inheritDoc */
144    public function getConfig(): array {
145        return [
146            'name' => 'ParserHook',
147            'tags' => [
148                [ 'name' => 'tag', 'handler' => self::class ],
149                [ 'name' => 'tåg', 'handler' => self::class ],
150                [ 'name' => 'statictag', 'handler' => self::class ],
151                [ 'name' => 'asidetag', 'handler' => self::class ],
152                [ 'name' => 'pwraptest', 'handler' => self::class ],
153                [
154                    'name' => 'divtag',
155                    'handler' => self::class,
156                    'options' => [
157                        'outputHasCoreMwDomSpecMarkup' => true,
158                    ],
159                ],
160                [
161                    'name' => 'spantag',
162                    'handler' => self::class,
163                    'options' => [
164                        'outputHasCoreMwDomSpecMarkup' => true,
165                    ],
166                ],
167                [
168                    'name' => 'embedtag',
169                    'handler' => self::class,
170                    'options' => [
171                        'wt2html' => [
172                            'embedsDomInAttributes' => true,
173                            'customizesDataMw' => true,
174                        ],
175                        'outputHasCoreMwDomSpecMarkup' => true,
176                    ],
177                ],
178                [
179                    'name' => 'sealtag',
180                    'handler' => self::class,
181                    'options' => [
182                        'wt2html' => [
183                            'unpackOutput' => false,
184                        ],
185                    ],
186                ],
187            ],
188            'domProcessors' => [
189                ParserHookProcessor::class
190            ]
191        ];
192    }
193}