Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
PWrapState
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 3
132
0.00% covered (danger)
0.00%
0 / 1
 reset
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 processOptionalNode
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 unwrapTrailingPWrapOptionalNodes
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2declare( strict_types = 1 );
3
4namespace Wikimedia\Parsoid\Wt2Html\PP\Processors;
5
6use Wikimedia\Parsoid\DOM\Element;
7use Wikimedia\Parsoid\DOM\Node;
8use Wikimedia\Parsoid\Utils\DOMUtils;
9
10class PWrapState {
11
12    private const RANGE_TYPE_RE = '!^mw:(Transclusion(/|$)|Param(/|$)|Annotation/)!';
13
14    /** @var ?Element */
15    public $p = null;
16
17    /** @var bool */
18    private $hasOptionalNode = false;
19
20    /**
21     * About ids of starts we've seen in this paragraph
22     *
23     * @var array
24     */
25    private $seenStarts = [];
26
27    /**
28     * Unwrap + reset
29     */
30    public function reset() {
31        $this->unwrapTrailingPWrapOptionalNodes();
32
33        $this->p = null;
34        $this->hasOptionalNode = false;
35        $this->seenStarts = [];
36    }
37
38    /**
39     * Record that we've encountered an optional node to potentially unwrap
40     *
41     * @param Node $n
42     */
43    public function processOptionalNode( Node $n ) {
44        $t = DOMUtils::matchNameAndTypeOf( $n, 'meta', self::RANGE_TYPE_RE );
45        $this->hasOptionalNode = (bool)$t || $this->hasOptionalNode;
46        if ( $t && !str_ends_with( $t, '/End' ) ) {
47            '@phan-var Element $n';  // @var Element $n
48            $this->seenStarts[$n->getAttribute( 'about' )] = true;
49        }
50    }
51
52    /**
53     * Unwrap a run of trailing nodes that don't need p-wrapping.
54     * This only matters for meta tags representing transclusions
55     * and annotations. Unwrapping can prevent unnecessary expansion
56     * of template/annotation ranges.
57     */
58    private function unwrapTrailingPWrapOptionalNodes() {
59        if ( $this->hasOptionalNode ) {
60            $lastChild = $this->p->lastChild;
61            while ( PWrap::pWrapOptional( $lastChild ) ) {
62                $t = DOMUtils::matchNameAndTypeOf( $lastChild, 'meta', self::RANGE_TYPE_RE );
63                if ( $t && str_ends_with( $t, '/End' ) ) {
64                    '@phan-var Element $lastChild';  // @var Element $lastChild
65                    // Check if one of its prior siblings has a matching opening tag.
66                    // If so, we are done with unwrapping here since we don't want to
67                    // hoist this closing tag by itself.
68                    $aboutId = $lastChild->getAttribute( 'about' );
69                    if ( $this->seenStarts[$aboutId] ?? null ) {
70                        break;
71                    }
72                }
73                $this->p->parentNode->insertBefore( $lastChild, $this->p->nextSibling );
74                $lastChild = $this->p->lastChild;
75            }
76        }
77    }
78
79}