• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dg / texy / 29654833201

18 Jul 2026 04:09PM UTC coverage: 93.039% (+0.04%) from 93.004%
29654833201

push

github

dg
Restored test coverage dropped during the AST migration

The migration removed five test files coupled to v3 contracts (block,
content-model, formatter-indent, html, latte) with the intent to bring
them back once the output layer settled. Restored here, ported to the
AST-era API; latte and most of content-model pass unchanged.

Expected outputs were re-derived and every difference against the v3
files reviewed case by case. The differences fall into the intentional
categories: list items merge continuation lines, whitespace-sensitive
typography follows visible length instead of protection-mark key length,
rejected tags are escaped consistently (both halves of a pair) with
typography applied to the escaped text, paragraphs of escaped markup are
<p>-wrapped, and <p> inside <form> is preserved. Inner texysource
fragments are parsed without the transform phase, so their passthrough
tags stay live - a documented wrinkle.

content-model.phpt again guards the WellFormer content model, nesting
prohibitions, transparent and unknown elements and auto-closing in the
public suite, independently of the private regression corpus.

3248 of 3491 relevant lines covered (93.04%)

0.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.92
/src/Texy/Modules/BlockModule.php
1
<?php declare(strict_types=1);
2

3
/**
4
 * This file is part of the Texy! (https://texy.nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
namespace Texy\Modules;
9

10
use Texy;
11
use Texy\Helpers;
12
use Texy\Nodes\BlockNode;
13
use Texy\Nodes\CodeBlockNode;
14
use Texy\Nodes\CommentNode;
15
use Texy\Nodes\SectionNode;
16
use Texy\ParseContext;
17
use Texy\Position;
18
use Texy\Syntax;
19
use function strlen, trim;
20

21

22
/**
23
 * Processes special blocks (/-- code, html, text, div, etc.).
24
 */
25
final class BlockModule extends Texy\Module
26
{
27
        public function __construct(
1✔
28
                private Texy\Texy $texy,
29
        ) {
30
                $texy->allowed[Syntax::BlockDefault] = true;
1✔
31
                $texy->allowed[Syntax::BlockPre] = true;
1✔
32
                $texy->allowed[Syntax::BlockCode] = true;
1✔
33
                $texy->allowed[Syntax::BlockHtml] = true;
1✔
34
                $texy->allowed[Syntax::BlockText] = true;
1✔
35
                $texy->allowed[Syntax::BlockTexySource] = true;
1✔
36
                $texy->allowed[Syntax::BlockComment] = true;
1✔
37
                $texy->allowed[Syntax::BlockDiv] = true;
1✔
38
        }
1✔
39

40

41
        public function beforeParse(string &$text): void
1✔
42
        {
43
                $this->texy->registerBlockPattern(
1✔
44
                        $this->parse(...),
1✔
45
                        '~^
46
                                /--++ \ *+                    # opening tag /--
47
                                (.*)                          # content type (1)
48
                                ' . Texy\Patterns::MODIFIER_H . '? # modifier (2)
1✔
49
                                $
50
                                ((?:                         # content (3)
51
                                        \n (?0) |                # recursive nested blocks
52
                                        \n.*+                    # or any content
53
                                )*)
54
                                (?:
55
                                        \n \\\--.* $ |           # closing tag
56
                                        \z                       # or end of input
57
                                )
58
                        ~mUi',
59
                        Syntax::Blocks,
1✔
60
                );
61
        }
1✔
62

63

64
        /**
65
         * Parses blocks /--foo
66
         * @param  array<?string>  $matches
67
         * @param  array<?int>  $offsets
68
         */
69
        public function parse(ParseContext $context, array $matches, array $offsets): ?BlockNode
1✔
70
        {
71
                /** @var array{string, string, ?string, string} $matches */
72
                [, $mParam, $mMod, $mContent] = $matches;
1✔
73

74
                $mod = Texy\Modifier::parse($mMod);
1✔
75
                $parts = Texy\Regexp::split($mParam, '~\s+~', limit: 2);
1✔
76
                $blocktype = empty($parts[0]) ? Syntax::BlockDefault : 'block/' . $parts[0];
1✔
77
                $param = empty($parts[1]) ? null : $parts[1];
1✔
78

79
                $content = Helpers::outdent($mContent);
1✔
80
                $position = new Position($offsets[0], strlen($matches[0]));
1✔
81

82
                if ($blocktype === Syntax::BlockCode) {
1✔
83
                        return new CodeBlockNode('code', $content, $param, $mod, $position);
1✔
84

85
                } elseif ($blocktype === Syntax::BlockDefault || $blocktype === Syntax::BlockPre) {
1✔
86
                        return new CodeBlockNode($blocktype === Syntax::BlockPre ? 'pre' : 'default', $content, $param, $mod, $position);
1✔
87

88
                } elseif ($blocktype === Syntax::BlockComment) {
1✔
89
                        return new CommentNode($content, $position);
1✔
90

91
                } elseif ($blocktype === Syntax::BlockHtml) {
1✔
92
                        // html/text blocks don't use outdent - preserve original indentation
93
                        return new CodeBlockNode('html', trim($mContent, "\n"), null, $mod, $position);
1✔
94

95
                } elseif ($blocktype === Syntax::BlockText) {
1✔
96
                        // html/text blocks don't use outdent - preserve original indentation
97
                        return new CodeBlockNode('text', trim($mContent, "\n"), null, $mod, $position);
1✔
98

99
                } elseif ($blocktype === Syntax::BlockDiv) {
1✔
100
                        [$content, $map] = Texy\OffsetMap::outdentLines(
1✔
101
                                Texy\OffsetMap::linesOf($mContent, $offsets[3] ?? 0),
1✔
102
                                firstLine: true,
1✔
103
                        );
104
                        if ($content === '') {
1✔
105
                                return null;
×
106
                        }
107
                        $parsed = $context->parseBlock($content);
1✔
108
                        $map->applyTo($parsed);
1✔
109
                        return new SectionNode($parsed, 'div', $mod, $position);
1✔
110

111
                } elseif ($blocktype === Syntax::BlockTexySource) {
1✔
112
                        // Store raw texy content, will be parsed and displayed as HTML source in handler
113
                        $content = Helpers::outdent($mContent);
1✔
114
                        if ($content === '') {
1✔
115
                                return null;
×
116
                        }
117
                        return new CodeBlockNode('texysource', $content, null, $mod, $position);
1✔
118
                }
119

120
                return null;
1✔
121
        }
122
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc