Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 42
RemexPipeline
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 6
110
0.00% covered (danger)
0.00%
0 / 42
 __construct
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 19
 insertUnfosteredMeta
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 6
 insertImplicitStartTag
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 insertExplicitStartTag
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
 insertExplicitEndTag
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
 isFosterablePosition
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
<?php
declare( strict_types = 1 );
namespace Wikimedia\Parsoid\Wt2Html\TreeBuilder;
use Wikimedia\Parsoid\Config\Env;
use Wikimedia\Parsoid\Core\InternalException;
use Wikimedia\Parsoid\DOM\Document;
use Wikimedia\Parsoid\DOM\Element;
use Wikimedia\Parsoid\Wikitext\Consts;
use Wikimedia\RemexHtml\Tokenizer\PlainAttributes;
use Wikimedia\RemexHtml\Tokenizer\Tokenizer;
use Wikimedia\RemexHtml\TreeBuilder\Dispatcher;
use Wikimedia\RemexHtml\TreeBuilder\TreeBuilder;
use Wikimedia\RemexHtml\TreeBuilder\TreeMutationTracer;
class RemexPipeline {
    /** @var Dispatcher */
    public $dispatcher;
    /** @var TreeBuilder */
    public $treeBuilder;
    /** @var TreeMutationRelay */
    private $relay;
    /** @var DOMBuilder */
    public $domBuilder;
    /** @var Document */
    public $doc;
    private $nextFakeLength = 1;
    /**
     * Create a RemexHtml pipeline
     *
     * Since we do our own tokenizing, the Dispatcher is called directly to push
     * data into the pipeline. A RemexHtml Tokenizer is only needed to provide
     * stub handling for certain TreeBuilder callbacks. Those callbacks are
     * required by the HTML 5  spec -- we get away with ignoring them because
     * we are not actually parsing HTML.
     *
     * @param Env $env
     */
    public function __construct( Env $env ) {
        $this->domBuilder = new DOMBuilder;
        $this->relay = new TreeMutationRelay( $this->domBuilder );
        if ( $env->hasTraceFlag( 'remex' ) ) {
            $tracer = new TreeMutationTracer(
                $this->relay,
                static function ( $msg ) use ( $env ) {
                    $env->log( 'trace/remex', $msg );
                }
            );
        } else {
            $tracer = $this->relay;
        }
        $this->treeBuilder = new TreeBuilder( $tracer );
        $this->dispatcher = new Dispatcher( $this->treeBuilder );
        // Create dummy Tokenizer
        $tokenizer = new Tokenizer( $this->dispatcher, '', [ 'ignoreErrors' => true ] );
        $this->dispatcher->startDocument( $tokenizer, null, null );
        $this->dispatcher->doctype( 'html', '', '', false, 0, 0 );
        $this->dispatcher->startTag( 'body', new PlainAttributes(), false, 0, 0 );
        $doc = $this->domBuilder->getFragment();
        if ( $doc instanceof Document ) {
            $this->doc = $doc;
        } else {
            throw new InternalException( 'Invalid document type' );
        }
    }
    /**
     * Dispatch a meta tag in such a way that it won't be fostered even if the
     * currently open element is a table. This replaces the old comment hack.
     *
     * @param array $attribs
     */
    public function insertUnfosteredMeta( array $attribs ) {
        $this->dispatcher->flushTableText();
        $this->dispatcher->inHead->startTag(
            'meta',
            new Attributes( $this->doc, $attribs ),
            false, 0, 0
        );
    }
    /**
     * Dispatch a start tag and consider the generated element to be
     * auto-inserted.
     *
     * @param string $name
     * @param array $attribs
     * @param bool $selfClose
     */
    public function insertImplicitStartTag(
        string $name, array $attribs, bool $selfClose = false
    ): void {
        $attribsObj = new Attributes( $this->doc, $attribs );
        $this->dispatcher->startTag( $name, $attribsObj, $selfClose, 0, 0 );
    }
    /**
     * Dispatch a start tag and consider the generated element to be explicit,
     * not auto-inserted. Return that element. If no element was created,
     * return null.
     *
     * @param string $name
     * @param array $attribs
     * @param bool $selfClose
     * @return Element|null
     */
    public function insertExplicitStartTag(
        string $name, array $attribs, bool $selfClose = false
    ): ?Element {
        $attribsObj = new Attributes( $this->doc, $attribs );
        $this->relay->matchStartTag( $attribsObj );
        $this->dispatcher->startTag( $name, $attribsObj, $selfClose, 0, 0 );
        $element = $this->relay->getMatchedElement();
        $this->relay->resetMatch();
        return $element;
    }
    /**
     * Dispatch an end tag, and cause the element to be explicitly ended,
     * i.e. without autoInsertedEnd. Return the element which was ended by the
     * tag, or null if no element was matched.
     *
     * @param string $name
     * @param bool $isHTML
     * @return Element|null
     */
    public function insertExplicitEndTag(
        string $name, bool $isHTML
    ): ?Element {
        $fakeLength = $this->nextFakeLength++;
        $this->relay->matchEndTag( $fakeLength, $isHTML );
        $this->dispatcher->endTag( $name, 0, $fakeLength );
        $element = $this->relay->getMatchedElement();
        $this->relay->resetMatch();
        return $element;
    }
    /**
     * Determine if the TreeBuilder is in a fosterable position, i.e. insertion
     * of a text node will cause fostering of that text.
     *
     * @return bool
     */
    public function isFosterablePosition() {
        $openElement = $this->treeBuilder->stack->current;
        return isset( Consts::$HTML['FosterablePosition'][$openElement->htmlName] );
    }
}