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

dg / texy / 22262589061

21 Feb 2026 07:04PM UTC coverage: 92.991% (+1.8%) from 91.178%
22262589061

push

github

dg
LinkModule: deprecated label and modifiers in link definitions

3 of 3 new or added lines in 1 file covered. (100.0%)

126 existing lines in 22 files now uncovered.

2083 of 2240 relevant lines covered (92.99%)

0.93 hits per line

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

98.18
/src/Texy/Modules/AutolinkModule.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\HandlerInvocation;
12
use Texy\InlineParser;
13
use Texy\Link;
14
use Texy\Patterns;
15
use Texy\Regexp;
16
use function iconv_strlen, iconv_substr, str_replace, strncasecmp;
17

18

19
/**
20
 * Autodetects URLs and email addresses in text.
21
 */
22
final class AutolinkModule extends Texy\Module
23
{
24
        /** shorten URLs to more readable form? */
25
        public bool $shorten = true;
26

27

28
        public function __construct(
1✔
29
                private Texy\Texy $texy,
30
        ) {
31
                $texy->addHandler('linkEmail', $this->solveUrlEmail(...));
1✔
32
                $texy->addHandler('linkURL', $this->solveUrlEmail(...));
1✔
33
        }
1✔
34

35

36
        public function beforeParse(string &$text): void
1✔
37
        {
38
                // direct url; characters not allowed in URL <>[\]^`{|}
39
                $this->texy->registerLinePattern(
1✔
40
                        $this->parseUrlEmail(...),
1✔
41
                        '~
42
                                (?<= ^ | [\s([<:\x17] )            # must be preceded by these chars
43
                                (?: https?:// | www\. | ftp:// )   # protocol or www
44
                                [0-9.' . Patterns::CHAR . '-]      # first char
1✔
45
                                [/\d' . Patterns::CHAR . '+.\~%&?@=_:;#$!,*()\x{ad}-]{1,1000}  # URL body
1✔
46
                                [/\d' . Patterns::CHAR . '+\~?@=_#$*]  # last char
1✔
47
                        ~',
48
                        'link/url',
1✔
49
                        '~(?: https?:// | www\. | ftp://)~',
1✔
50
                );
51

52
                // direct email
53
                $this->texy->registerLinePattern(
1✔
54
                        $this->parseUrlEmail(...),
1✔
55
                        '~
56
                                (?<= ^ | [\s([<\x17] )             # must be preceded by these chars
57
                                ' . Patterns::EMAIL . '
1✔
58
                        ~',
59
                        'link/email',
1✔
60
                        '~' . Patterns::EMAIL . '~',
1✔
61
                );
62
        }
1✔
63

64

65
        /**
66
         * Parses http://davidgrudl.com david@grudl.com
67
         * @param  array<?string>  $matches
68
         */
69
        public function parseUrlEmail(InlineParser $parser, array $matches, string $name): Texy\HtmlElement|string|null
1✔
70
        {
71
                [$mURL] = $matches;
1✔
72
                // [0] => URL
73

74
                $link = new Link($mURL);
1✔
75
                $this->texy->linkModule->checkLink($link);
1✔
76

77
                return $this->texy->invokeAroundHandlers(
1✔
78
                        $name === 'link/email' ? 'linkEmail' : 'linkURL',
1✔
79
                        $parser,
80
                        [$link],
1✔
81
                );
82
        }
83

84

85
        /**
86
         * Handler for URL/email - creates textual content and link element.
87
         */
88
        private function solveUrlEmail(HandlerInvocation $invocation, Link $link): Texy\HtmlElement|string|null
1✔
89
        {
90
                $content = $this->textualUrl($link);
1✔
91
                $content = $this->texy->protect($content, Texy\Texy::CONTENT_TEXTUAL);
1✔
92
                return $this->texy->linkModule->solve(null, $link, $content);
1✔
93
        }
94

95

96
        /**
97
         * Returns textual representation of URL.
98
         */
99
        public function textualUrl(Link $link): string
1✔
100
        {
101
                if ($this->texy->obfuscateEmail && Regexp::match($link->raw, '~^' . Patterns::EMAIL . '$~')) { // email
1✔
102
                        return str_replace('@', '&#64;<!-- -->', $link->raw);
1✔
103
                }
104

105
                if ($this->shorten && Regexp::match($link->raw, '~^(https?://|ftp://|www\.|/)~i')) {
1✔
106
                        $raw = strncasecmp($link->raw, 'www.', 4) === 0
1✔
107
                                ? 'none://' . $link->raw
1✔
108
                                : $link->raw;
1✔
109

110
                        // parse_url() in PHP damages UTF-8 - use regular expression
111
                        if (!($parts = Regexp::match($raw, '~^
1✔
112
                                (?: (?P<scheme> [a-z]+ ) : )?
113
                                (?: // (?P<host> [^/?#]+ ) )?
114
                                (?P<path> (?: / | ^ ) (?! / ) [^?#]* )?
115
                                (?: \? (?P<query> [^#]* ) )?
116
                                (?: \# (?P<fragment> .* ) )?
117
                                $
118
                        ~'))) {
UNCOV
119
                                return $link->raw;
×
120
                        }
121

122
                        $res = '';
1✔
123
                        if ($parts['scheme'] !== null && $parts['scheme'] !== 'none') {
1✔
124
                                $res .= $parts['scheme'] . '://';
1✔
125
                        }
126

127
                        if ($parts['host'] !== null) {
1✔
128
                                $res .= $parts['host'];
1✔
129
                        }
130

131
                        if ($parts['path'] !== null) {
1✔
132
                                $res .= (iconv_strlen($parts['path'], 'UTF-8') > 16 ? ("/\u{2026}" . iconv_substr($parts['path'], -12, 12, 'UTF-8')) : $parts['path']);
1✔
133
                        }
134

135
                        if ($parts['query'] > '') {
1✔
136
                                $res .= iconv_strlen($parts['query'], 'UTF-8') > 4
1✔
137
                                        ? "?\u{2026}"
1✔
138
                                        : ('?' . $parts['query']);
1✔
139
                        } elseif ($parts['fragment'] > '') {
1✔
140
                                $res .= iconv_strlen($parts['fragment'], 'UTF-8') > 4
1✔
141
                                        ? "#\u{2026}"
1✔
142
                                        : ('#' . $parts['fragment']);
1✔
143
                        }
144

145
                        return $res;
1✔
146
                }
147

148
                return $link->raw;
1✔
149
        }
150
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc