• 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

96.88
/src/Texy/Modules/EmoticonModule.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\Nodes\EmoticonNode;
12
use Texy\ParseContext;
13
use Texy\Position;
14
use Texy\Syntax;
15
use function strlen;
16

17

18
/**
19
 * Replaces emoticons with images or Unicode characters.
20
 */
21
final class EmoticonModule extends Texy\Module
22
{
23
        /** @var array<string, string> emoticon → emoji/image mapping */
24
        public array $icons = [
25
                ':-)' => '🙂',
26
                ':-(' => '☹',
27
                ';-)' => '😉',
28
                ':-D' => '😁',
29
                '8-O' => '😮',
30
                '8-)' => '😄',
31
                ':-?' => '😕',
32
                ':-x' => '😶',
33
                ':-P' => '😛',
34
                ':-|' => '😐',
35
        ];
36

37

38
        public function __construct(
1✔
39
                private Texy\Texy $texy,
40
        ) {
41
                $texy->allowed[Syntax::Emoticon] = false;
1✔
42
                $texy->addHandler('afterParse', $this->resolveEmoticons(...));
1✔
43
        }
1✔
44

45

46
        /**
47
         * Writes resolved emoji into EmoticonNode so the AST is semantically complete
48
         * and generators need not reach into this module.
49
         */
50
        public function resolveEmoticons(Texy\Nodes\DocumentNode $doc): void
1✔
51
        {
52
                if (empty($this->texy->allowed[Syntax::Emoticon])) { // disabled → no EmoticonNodes in AST
1✔
53
                        return;
1✔
54
                }
55

56
                (new Texy\NodeTraverser)->traverse($doc, function (Texy\Node $node): ?int {
1✔
57
                        if ($node instanceof EmoticonNode) {
1✔
58
                                $node->resolved = $this->icons[$node->emoticon] ?? $node->emoticon;
1✔
59
                        }
60
                        return null;
1✔
61
                });
1✔
62
        }
1✔
63

64

65
        public function beforeParse(string &$text): void
1✔
66
        {
67
                if (str_contains(implode('', $this->icons), '.')) {
1✔
68
                        trigger_error('EmoticonModule: using image files is deprecated, use Unicode characters instead.', E_USER_DEPRECATED);
1✔
69
                }
70

71
                $icons = $this->icons;
1✔
72
                krsort($icons);
1✔
73
                $pattern = [];
1✔
74
                foreach ($icons as $key => $foo) {
1✔
75
                        $pattern[] = Texy\Regexp::quote($key) . '+'; // last char can be repeated
1✔
76
                }
77

78
                $this->texy->registerLinePattern(
1✔
79
                        $this->parse(...),
1✔
80
                        '~
81
                                (?<= ^ | [\x00-\x20] )
82
                                (' . implode('|', $pattern) . ')
1✔
83
                        ~',
84
                        Syntax::Emoticon,
1✔
85
                );
86
        }
1✔
87

88

89
        /**
90
         * Parses :-).
91
         * @param  array<?string>  $matches
92
         * @param  array<?int>  $offsets
93
         */
94
        public function parse(ParseContext $context, array $matches, array $offsets): ?EmoticonNode
1✔
95
        {
96
                /** @var array{string, string} $matches */
97
                $match = $matches[0];
1✔
98

99
                // Find the closest match
100
                foreach ($this->icons as $emoticon => $_) {
1✔
101
                        if (str_starts_with($match, $emoticon)) {
1✔
102
                                return new EmoticonNode($emoticon, new Position($offsets[0], strlen($matches[0])));
1✔
103
                        }
104
                }
105

106
                return null;
×
107
        }
108
}
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