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