Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProcessTreeBuilderFixups
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 2
156
0.00% covered (danger)
0.00%
0 / 1
 removeAutoInsertedEmptyTags
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
132
 run
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace Wikimedia\Parsoid\Wt2Html\PP\Processors;
5
6use Wikimedia\Parsoid\Config\Env;
7use Wikimedia\Parsoid\DOM\Element;
8use Wikimedia\Parsoid\DOM\Node;
9use Wikimedia\Parsoid\Utils\DiffDOMUtils;
10use Wikimedia\Parsoid\Utils\DOMDataUtils;
11use Wikimedia\Parsoid\Utils\WTUtils;
12use Wikimedia\Parsoid\Wt2Html\Frame;
13use Wikimedia\Parsoid\Wt2Html\Wt2HtmlDOMProcessor;
14
15class ProcessTreeBuilderFixups implements Wt2HtmlDOMProcessor {
16
17    private static function removeAutoInsertedEmptyTags( Frame $frame, Node $node ): void {
18        $c = $node->firstChild;
19        while ( $c !== null ) {
20            // FIXME: Encapsulation only happens after this phase, so you'd think
21            // we wouldn't encounter any, but the html pre tag inserts extension
22            // content directly, rather than passing it through as a fragment for
23            // later unpacking.  Same as above.
24            if ( WTUtils::isEncapsulationWrapper( $c ) ) {
25                $c = WTUtils::skipOverEncapsulatedContent( $c );
26                continue;
27            }
28
29            if ( $c instanceof Element ) {
30                self::removeAutoInsertedEmptyTags( $frame, $c );
31                $dp = DOMDataUtils::getDataParsoid( $c );
32
33                // We do this down here for all elements since the quote transformer
34                // also marks up elements as auto-inserted and we don't want to be
35                // constrained by any conditions.  Further, this pass should happen
36                // before paragraph wrapping on the dom, since we don't want this
37                // stripping to result in empty paragraphs.
38
39                // Delete empty auto-inserted elements
40                if ( !empty( $dp->autoInsertedStart ) && !empty( $dp->autoInsertedEnd ) &&
41                    ( !$c->hasChildNodes() ||
42                        ( DiffDOMUtils::hasNChildren( $c, 1 ) &&
43                            !( $c->firstChild instanceof Element ) &&
44                            preg_match( '/^\s*$/D', $c->textContent )
45                        )
46                    )
47                ) {
48                    $next = $c->nextSibling;
49                    if ( $c->firstChild ) {
50                        // migrate the ws out
51                        $c->parentNode->insertBefore( $c->firstChild, $c );
52                    }
53                    $c->parentNode->removeChild( $c );
54                    $c = $next;
55                    continue;
56                }
57            }
58
59            $c = $c->nextSibling;
60        }
61    }
62
63    /**
64     * @inheritDoc
65     */
66    public function run(
67        Env $env, Node $root, array $options = [], bool $atTopLevel = false
68    ): void {
69        self::removeAutoInsertedEmptyTags( $options['frame'], $root );
70    }
71}