@@ -84,7 +84,7 @@ public function tokenize(string $markdown): array
8484 $ fencedLines = [];
8585 $ fenceChar = '' ;
8686 $ fenceLength = 0 ;
87- $ pendingToken = null ;
87+ $ pendingLines = [] ;
8888 $ pendingLinkDef = null ; // LINK_DEFINITION token awaiting a possible next-line title
8989
9090 $ inHtmlBlock = false ;
@@ -149,10 +149,10 @@ public function tokenize(string $markdown): array
149149
150150 if ($ inColumnsBlock ) {
151151 if (preg_match (self ::PATTERN_COLUMNS_CLOSE , $ line )) {
152- if ($ pendingToken !== null ) {
153- $ tokens [] = $ pendingToken ;
154- $ pendingToken = null ;
152+ foreach ($ pendingLines as $ pt ) {
153+ $ tokens [] = $ pt ;
155154 }
155+ $ pendingLines = [];
156156 $ tokens [] = new Token (
157157 TokenType::COLUMNS_CONTAINER ,
158158 '' ,
@@ -176,10 +176,10 @@ public function tokenize(string $markdown): array
176176 }
177177
178178 if (preg_match (self ::PATTERN_COLUMNS_OPEN , $ line )) {
179- if ($ pendingToken !== null ) {
180- $ tokens [] = $ pendingToken ;
181- $ pendingToken = null ;
179+ foreach ($ pendingLines as $ pt ) {
180+ $ tokens [] = $ pt ;
182181 }
182+ $ pendingLines = [];
183183 $ inColumnsBlock = true ;
184184 $ columnsSepFound = false ;
185185 $ columnsLeftLines = [];
@@ -189,10 +189,10 @@ public function tokenize(string $markdown): array
189189
190190 if ($ inFencedBlock ) {
191191 if (preg_match ('/^ {0,3} ' . preg_quote ($ fenceChar , '/ ' ) . '{ ' . $ fenceLength . ',}\s*$/ ' , $ line )) {
192- if ($ pendingToken !== null ) {
193- $ tokens [] = $ pendingToken ;
194- $ pendingToken = null ;
192+ foreach ($ pendingLines as $ pt ) {
193+ $ tokens [] = $ pt ;
195194 }
195+ $ pendingLines = [];
196196 $ tokens [] = new Token (
197197 TokenType::FENCED_CODE ,
198198 implode ("\n" , $ fencedLines ),
@@ -210,10 +210,10 @@ public function tokenize(string $markdown): array
210210 }
211211
212212 if (preg_match (self ::PATTERN_FENCED_OPEN , $ line , $ m )) {
213- if ($ pendingToken !== null ) {
214- $ tokens [] = $ pendingToken ;
215- $ pendingToken = null ;
213+ foreach ($ pendingLines as $ pt ) {
214+ $ tokens [] = $ pt ;
216215 }
216+ $ pendingLines = [];
217217 $ inFencedBlock = true ;
218218 $ fencedLanguage = $ m [2 ];
219219 $ fencedLines = [];
@@ -226,10 +226,10 @@ public function tokenize(string $markdown): array
226226 // Must run before setext/paragraph logic so that block-level HTML tags
227227 // are not consumed as paragraphs.
228228 if (preg_match ($ this ->patternHtmlBlockStart , $ line )) {
229- if ($ pendingToken !== null ) {
230- $ tokens [] = $ pendingToken ;
231- $ pendingToken = null ;
229+ foreach ($ pendingLines as $ pt ) {
230+ $ tokens [] = $ pt ;
232231 }
232+ $ pendingLines = [];
233233 // Detect whether this is an HTML comment opener.
234234 $ isCommentStart = str_starts_with (ltrim ($ line ), '<!-- ' );
235235 $ isCommentClosed = $ isCommentStart && str_contains ($ line , '--> ' );
@@ -269,22 +269,22 @@ public function tokenize(string $markdown): array
269269 }
270270
271271 // Capture paragraph-active state before setext promotion may clear it.
272- $ hadPendingToken = $ pendingToken !== null ;
272+ $ hadPendingLines = $ pendingLines !== [] ;
273273
274- // Setext heading detection: a pending text line followed by === or ---
275- if ($ pendingToken !== null ) {
274+ // Setext heading detection: pending text lines followed by === or ---
275+ if ($ pendingLines !== [] ) {
276276 if (preg_match (self ::PATTERN_SETEXT_H1 , $ line )) {
277- $ tokens [] = new Token (TokenType::HEADING , $ pendingToken ->content , ['level ' => 1 ]);
278- $ pendingToken = null ;
277+ $ content = implode (' ' , array_map (fn (Token $ t ) => $ t ->content , $ pendingLines ));
278+ $ tokens [] = new Token (TokenType::HEADING , $ content , ['level ' => 1 ]);
279+ $ pendingLines = [];
279280 continue ;
280281 }
281282 if (preg_match (self ::PATTERN_SETEXT_H2 , $ line )) {
282- $ tokens [] = new Token (TokenType::HEADING , $ pendingToken ->content , ['level ' => 2 ]);
283- $ pendingToken = null ;
283+ $ content = implode (' ' , array_map (fn (Token $ t ) => $ t ->content , $ pendingLines ));
284+ $ tokens [] = new Token (TokenType::HEADING , $ content , ['level ' => 2 ]);
285+ $ pendingLines = [];
284286 continue ;
285287 }
286- $ tokens [] = $ pendingToken ;
287- $ pendingToken = null ;
288288 }
289289
290290 // Multiline link ref title (CommonMark §4.7): a LINK_DEFINITION with no title
@@ -342,7 +342,7 @@ public function tokenize(string $markdown): array
342342 // Start new indented code block (only when no paragraph was active,
343343 // and only when the line is not a list item — list items with leading spaces
344344 // are handled by matchLine() via PATTERN_UNORDERED_LIST / PATTERN_ORDERED_LIST).
345- if (!$ hadPendingToken
345+ if (!$ hadPendingLines
346346 && preg_match (self ::PATTERN_INDENTED_CODE , $ line , $ m )
347347 && !preg_match (self ::PATTERN_UNORDERED_LIST , $ line )
348348 && !preg_match (self ::PATTERN_ORDERED_LIST , $ line )
@@ -364,11 +364,10 @@ public function tokenize(string $markdown): array
364364 // A FOOTNOTE_DEFINITION token opens multi-line body accumulation.
365365 // Flush any pending setext heading candidate and pending link def first.
366366 if ($ token ->type === TokenType::FOOTNOTE_DEFINITION ) {
367- /** @psalm-suppress TypeDoesNotContainType @phpstan-ignore notIdentical.alwaysFalse */
368- if ($ pendingToken !== null ) {
369- $ tokens [] = $ pendingToken ;
370- $ pendingToken = null ;
367+ foreach ($ pendingLines as $ pt ) {
368+ $ tokens [] = $ pt ;
371369 }
370+ $ pendingLines = [];
372371 /** @psalm-suppress TypeDoesNotContainType @phpstan-ignore notIdentical.alwaysFalse */
373372 if ($ pendingLinkDef !== null ) {
374373 $ tokens [] = $ pendingLinkDef ;
@@ -382,10 +381,14 @@ public function tokenize(string $markdown): array
382381
383382 // A plain paragraph line is held as pending to allow setext promotion on the next line.
384383 if ($ token ->type === TokenType::PARAGRAPH && ($ line !== '' && !ctype_space ($ line ))) {
385- $ pendingToken = $ token ;
384+ $ pendingLines [] = $ token ;
386385 continue ;
387386 }
388387
388+ foreach ($ pendingLines as $ pt ) {
389+ $ tokens [] = $ pt ;
390+ }
391+ $ pendingLines = [];
389392 $ tokens [] = $ token ;
390393 }
391394
@@ -394,9 +397,9 @@ public function tokenize(string $markdown): array
394397 $ tokens [] = $ pendingLinkDef ;
395398 }
396399
397- // Flush any remaining pending token
398- if ($ pendingToken !== null ) {
399- $ tokens [] = $ pendingToken ;
400+ // Flush any remaining pending lines
401+ foreach ($ pendingLines as $ pt ) {
402+ $ tokens [] = $ pt ;
400403 }
401404
402405 // Flush any in-progress footnote definition body
0 commit comments