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