Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 52 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
TokenTransformManager | |
0.00% |
0 / 52 |
|
0.00% |
0 / 10 |
702 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
setPipelineId | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getFrame | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getOptions | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
addTransformer | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
shuttleTokensToEndOfStage | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
processChunk | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
156 | |||
resetState | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
process | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
processChunkily | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikimedia\Parsoid\Wt2Html; |
5 | |
6 | use Generator; |
7 | use Wikimedia\Parsoid\Config\Env; |
8 | use Wikimedia\Parsoid\Config\Profile; |
9 | use Wikimedia\Parsoid\Tokens\SelfclosingTagTk; |
10 | use Wikimedia\Parsoid\Utils\PHPUtils; |
11 | use Wikimedia\Parsoid\Wt2Html\TT\TokenHandler; |
12 | use Wikimedia\Parsoid\Wt2Html\TT\TraceProxy; |
13 | |
14 | /** |
15 | * Token transformation manager. Individual transformations |
16 | * implement the TokenHandler interface. The parser pipeline |
17 | * registers individual transformers. |
18 | * |
19 | * See https://www.mediawiki.org/wiki/Parsoid/Token_stream_transformations |
20 | * for more documentation. This abstract class could eventually be |
21 | * eliminated and the various token transforms just extend PipelineStage |
22 | * directly. |
23 | */ |
24 | class TokenTransformManager extends PipelineStage { |
25 | /** @var array */ |
26 | private $options; |
27 | |
28 | /** @var string */ |
29 | private $traceType = ""; |
30 | |
31 | /** @var bool */ |
32 | private $traceEnabled; |
33 | |
34 | /** @var TokenHandler[] */ |
35 | private $transformers = []; |
36 | |
37 | /** @var int For TraceProxy */ |
38 | public $tokenTimes = 0; |
39 | |
40 | /** @var Profile|null For TraceProxy */ |
41 | public $profile; |
42 | |
43 | /** @var bool */ |
44 | private $hasShuttleTokens = false; |
45 | |
46 | public function __construct( |
47 | Env $env, array $options, string $stageId, |
48 | ?PipelineStage $prevStage = null |
49 | ) { |
50 | parent::__construct( $env, $prevStage ); |
51 | $this->options = $options; |
52 | $this->pipelineId = null; |
53 | $this->traceType = 'trace/ttm:' . str_replace( 'TokenTransform', '', $stageId ); |
54 | $this->traceEnabled = $env->hasTraceFlags(); |
55 | } |
56 | |
57 | public function setPipelineId( int $id ): void { |
58 | parent::setPipelineId( $id ); |
59 | foreach ( $this->transformers as $transformer ) { |
60 | $transformer->setPipelineId( $id ); |
61 | } |
62 | } |
63 | |
64 | public function getFrame(): Frame { |
65 | return $this->frame; |
66 | } |
67 | |
68 | public function getOptions(): array { |
69 | return $this->options; |
70 | } |
71 | |
72 | /** |
73 | * @inheritDoc |
74 | */ |
75 | public function addTransformer( TokenHandler $t ): void { |
76 | if ( $this->traceEnabled ) { |
77 | $this->transformers[] = new TraceProxy( $this, $this->options, $this->traceType, $t ); |
78 | } else { |
79 | $this->transformers[] = $t; |
80 | } |
81 | } |
82 | |
83 | public function shuttleTokensToEndOfStage( array $toks ): array { |
84 | $this->hasShuttleTokens = true; |
85 | $ttmEnd = new SelfclosingTagTk( 'mw:ttm-end' ); |
86 | $ttmEnd->dataParsoid->getTemp()->shuttleTokens = $toks; |
87 | return [ $ttmEnd ]; |
88 | } |
89 | |
90 | /** |
91 | * Push the tokens through all the registered transformers. |
92 | * @inheritDoc |
93 | */ |
94 | public function processChunk( array $tokens ): ?array { |
95 | // Trivial case |
96 | if ( !$tokens ) { |
97 | return $tokens; |
98 | } |
99 | |
100 | $startTime = null; |
101 | $profile = $this->profile = $this->env->profiling() ? $this->env->getCurrentProfile() : null; |
102 | |
103 | if ( $profile ) { |
104 | $startTime = microtime( true ); |
105 | $this->tokenTimes = 0; |
106 | } |
107 | |
108 | foreach ( $this->transformers as $transformer ) { |
109 | if ( !$transformer->isDisabled() ) { |
110 | if ( !$tokens ) { |
111 | break; |
112 | } |
113 | $tokens = $transformer->process( $tokens ); |
114 | } |
115 | } |
116 | |
117 | // Unpack tokens that were shuttled to the end of the stage. This happens |
118 | // when we used a nested pipeline to process tokens to the end of the |
119 | // current stage but then they need to be reinserted into the stream |
120 | // and we don't want them to be processed by subsequent handlers again. |
121 | if ( $this->hasShuttleTokens ) { |
122 | $this->hasShuttleTokens = false; |
123 | $accum = []; |
124 | foreach ( $tokens as $i => $t ) { |
125 | if ( $t instanceof SelfclosingTagTk && $t->getName() === 'mw:ttm-end' ) { |
126 | $toks = $t->dataParsoid->getTemp()->shuttleTokens; |
127 | PHPUtils::pushArray( $accum, $toks ); |
128 | } else { |
129 | $accum[] = $t; |
130 | } |
131 | } |
132 | $tokens = $accum; |
133 | } |
134 | |
135 | if ( $profile ) { |
136 | $profile->bumpTimeUse( 'TTM', |
137 | ( microtime( true ) - $startTime ) * 1000 - $this->tokenTimes, |
138 | 'TTM' ); |
139 | } |
140 | |
141 | return $tokens; |
142 | } |
143 | |
144 | /** |
145 | * @inheritDoc |
146 | */ |
147 | public function resetState( array $opts ): void { |
148 | $this->hasShuttleTokens = false; |
149 | parent::resetState( $opts ); |
150 | foreach ( $this->transformers as $transformer ) { |
151 | $transformer->resetState( $opts ); |
152 | } |
153 | } |
154 | |
155 | /** |
156 | * See PipelineStage::process docs as well. This doc block refines |
157 | * the generic arg types to be specific to this pipeline stage. |
158 | * |
159 | * Process a chunk of tokens. |
160 | * |
161 | * @param array $tokens Array of tokens to process |
162 | * @param array $opts |
163 | * @return array Returns the array of processed tokens |
164 | */ |
165 | public function process( $tokens, array $opts ): array { |
166 | return $this->processChunk( $tokens ); |
167 | } |
168 | |
169 | /** |
170 | * @inheritDoc |
171 | */ |
172 | public function processChunkily( $input, array $opts ): Generator { |
173 | if ( $this->prevStage ) { |
174 | foreach ( $this->prevStage->processChunkily( $input, $opts ) as $chunk ) { |
175 | '@phan-var array $chunk'; // @var array $chunk |
176 | yield $this->processChunk( $chunk ); |
177 | } |
178 | } else { |
179 | yield $this->process( $input, $opts ); |
180 | } |
181 | } |
182 | } |