Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
LineBasedHandler
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 4
110
0.00% covered (danger)
0.00%
0 / 1
 onTag
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onAny
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onEnd
n/a
0 / 0
n/a
0 / 0
0
 onNewline
n/a
0 / 0
n/a
0 / 0
0
 onCompoundTk
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 process
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2declare( strict_types = 1 );
3
4namespace Wikimedia\Parsoid\Wt2Html\TT;
5
6use Wikimedia\Assert\UnreachableException;
7use Wikimedia\Parsoid\Tokens\CommentTk;
8use Wikimedia\Parsoid\Tokens\CompoundTk;
9use Wikimedia\Parsoid\Tokens\EmptyLineTk;
10use Wikimedia\Parsoid\Tokens\EOFTk;
11use Wikimedia\Parsoid\Tokens\NlTk;
12use Wikimedia\Parsoid\Tokens\Token;
13use Wikimedia\Parsoid\Tokens\XMLTagTk;
14
15/**
16 * These handlers process wikitext constructs that are line-based.
17 * They are interesed in all tokens and on encountering a newline,
18 * they process the "line" in some fashion. In somes cases, the
19 * handler is only triggered on seeing a specific tag/token.
20 * Till that time, they ignore all tokens. (ex: list, indent-pre, quote)
21 *
22 * Ex: indent-pre, quote, paragraph, lists, token-stream-patcher
23 *
24 * They always implement the onEnd and onNewline handlers,
25 * with the onAny and onTag handlers being optional.
26 */
27abstract class LineBasedHandler extends TokenHandler {
28    protected bool $onAnyEnabled = true;
29
30    /**
31     * The handler may choose to process only specific kinds of tokens.
32     * For example, a list handler may only process 'listitem' TagTk tokens.
33     *
34     * @param XMLTagTk $token tag to be processed
35     * @return ?array<string|Token>
36     *   - null indicates that the token was passed-through
37     *     and it will be dispatched to the onAny handler
38     *   - an array indicates the token was transformed
39     *     and it will skip the onAny handler. The result array
40     *     may be the cumulative transformation of this token
41     *     and other previous tokens before this.
42     */
43    public function onTag( XMLTagTk $token ): ?array {
44        return null;
45    }
46
47    /**
48     * This handler is called for *all* tokens in the token stream except if:
49     * (a) the more specific handlers (onTag, onEnd, onNewline) returned
50     *     a non-null array which means the token was modified and
51     *     shouldn't be processed by the onAny handler.
52     * (b) onAnyEnabled is set to false (can be set by any of the above
53     *     specific handlers).
54     *
55     * @param Token|string $token Token to be processed
56     * @return ?array<string|Token>
57     *   - null indicates that the token was untransformed
58     *     and it will be added to this handler's output array.
59     *   - an array indicates the token was transformed
60     *     and the contents of the array will be added to this
61     *     handler's output array.
62     */
63    public function onAny( $token ): ?array {
64        return null;
65    }
66
67    /**
68     * This handler is called for EOF tokens only
69     * @param EOFTk $token EOF token to be processed
70     * @return ?array<string|Token>
71     *   - null indicates that the token was passed-through
72     *     and it will be dispatched to the onAny handler
73     *   - an array indicates the token was transformed
74     *     and it will skip the onAny handler. The result array
75     *     may be the cumulative transformation of this token
76     *     and other previous tokens before this.
77     */
78    abstract public function onEnd( EOFTk $token ): ?array;
79
80    /**
81     * This handler is called for newline tokens only
82     * @param NlTk $token Newline token to be processed
83     * @return ?array<string|Token>
84     *   - null indicates that the token was passed-through
85     *     and it will be dispatched to the onAny handler
86     *   - an array indicates the token was transformed
87     *     and it will skip the onAny handler. The result array
88     *     may be the cumulative transformation of this token
89     *     and other previous tokens before this.
90     */
91    abstract public function onNewline( NlTk $token ): ?array;
92
93    /**
94     * Process the compound token in a handler-specific way.
95     * - Some handlers might ignore it and pass it through
96     * - Some handlers might process its nested tokens and update it
97     * - Some handlers might process its nested tokens and flatten it
98     *
99     * To ensure that handlers that encounter compound tokens always
100     * have explicit handling for them, the default implementation
101     * here will throw an exception!
102     *
103     * NOTE: The only reason we are processing a handler here is because
104     * of needing to support profiling. For the profiling use case,
105     * we will be passing a TraceProxy instead of the handler itself.
106     */
107    public function onCompoundTk( CompoundTk $ctk, TokenHandler $tokensHandler ): ?array {
108        if ( $ctk instanceof EmptyLineTk ) {
109            return null;
110        }
111        throw new UnreachableException(
112            get_class( $this ) . ": Unsupported compound token."
113        );
114    }
115
116    /** @inheritDoc */
117    public function process( array $tokens ): array {
118        $accum = [];
119        foreach ( $tokens as $token ) {
120            $res = match ( true ) {
121                // Ordered from most likely to least likely for performance reasons
122                $token instanceof XMLTagTk => $this->onTag( $token ),
123                // Intentional duplicates to bail out as fast as possible
124                is_string( $token ) => null,
125                $token instanceof CommentTk => null,
126                $token instanceof NlTk => $this->onNewline( $token ),
127                $token instanceof CompoundTk => $this->onCompoundTk( $token, $this ),
128                $token instanceof EOFTk => $this->onEnd( $token ),
129                default => null
130            };
131
132            if ( $res === null && $this->onAnyEnabled ) {
133                $res = $this->onAny( $token );
134            }
135
136            if ( $res === null ) {
137                $accum[] = $token;
138            } else {
139                // Avoid array_merge() -- see https://w.wiki/3zvE
140                foreach ( $res as $t ) {
141                    $accum[] = $t;
142                }
143            }
144        }
145
146        return $accum;
147    }
148}