1<?php
2
3/*
4 * This file is part of the league/commonmark package.
5 *
6 * (c) Colin O'Dell <colinodell@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace League\CommonMark\Extension\Autolink;
13
14use League\CommonMark\Event\DocumentParsedEvent;
15use League\CommonMark\Inline\Element\Link;
16use League\CommonMark\Inline\Element\Text;
17
18final class EmailAutolinkProcessor
19{
20    const REGEX = '/([A-Za-z0-9.\-_+]+@[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_.]+)/';
21
22    /**
23     * @param DocumentParsedEvent $e
24     *
25     * @return void
26     */
27    public function __invoke(DocumentParsedEvent $e)
28    {
29        $walker = $e->getDocument()->walker();
30
31        while ($event = $walker->next()) {
32            $node = $event->getNode();
33            if ($node instanceof Text && !($node->parent() instanceof Link)) {
34                self::processAutolinks($node);
35            }
36        }
37    }
38
39    private static function processAutolinks(Text $node): void
40    {
41        $contents = \preg_split(self::REGEX, $node->getContent(), -1, PREG_SPLIT_DELIM_CAPTURE);
42
43        if ($contents === false || \count($contents) === 1) {
44            return;
45        }
46
47        $leftovers = '';
48        foreach ($contents as $i => $content) {
49            if ($i % 2 === 0) {
50                $text = $leftovers . $content;
51                if ($text !== '') {
52                    $node->insertBefore(new Text($leftovers . $content));
53                }
54
55                $leftovers = '';
56                continue;
57            }
58
59            // Does the URL end with punctuation that should be stripped?
60            if (\substr($content, -1) === '.') {
61                // Add the punctuation later
62                $content = \substr($content, 0, -1);
63                $leftovers = '.';
64            }
65
66            // The last character cannot be - or _
67            if (\in_array(\substr($content, -1), ['-', '_'])) {
68                $node->insertBefore(new Text($content . $leftovers));
69                $leftovers = '';
70                continue;
71            }
72
73            $node->insertBefore(new Link('mailto:' . $content, $content));
74        }
75
76        $node->detach();
77    }
78}
79