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\Extension\Mention\MentionParser;
15use League\CommonMark\Inline\Element\Link;
16use League\CommonMark\Inline\Parser\InlineParserInterface;
17use League\CommonMark\InlineParserContext;
18
19@trigger_error(sprintf('%s is deprecated; use %s instead', InlineMentionParser::class, MentionParser::class), E_USER_DEPRECATED);
20
21/**
22 * @deprecated Use MentionParser instead
23 */
24final class InlineMentionParser implements InlineParserInterface
25{
26    /** @var string */
27    private $linkPattern;
28
29    /** @var string */
30    private $handleRegex;
31
32    /**
33     * @param string $linkPattern
34     * @param string $handleRegex
35     */
36    public function __construct($linkPattern, $handleRegex = '/^[A-Za-z0-9_]+(?!\w)/')
37    {
38        $this->linkPattern = $linkPattern;
39        $this->handleRegex = $handleRegex;
40    }
41
42    public function getCharacters(): array
43    {
44        return ['@'];
45    }
46
47    public function parse(InlineParserContext $inlineContext): bool
48    {
49        $cursor = $inlineContext->getCursor();
50
51        // The @ symbol must not have any other characters immediately prior
52        $previousChar = $cursor->peek(-1);
53        if ($previousChar !== null && $previousChar !== ' ') {
54            // peek() doesn't modify the cursor, so no need to restore state first
55            return false;
56        }
57
58        // Save the cursor state in case we need to rewind and bail
59        $previousState = $cursor->saveState();
60
61        // Advance past the @ symbol to keep parsing simpler
62        $cursor->advance();
63
64        // Parse the handle
65        $handle = $cursor->match($this->handleRegex);
66        if (empty($handle)) {
67            // Regex failed to match; this isn't a valid Twitter handle
68            $cursor->restoreState($previousState);
69
70            return false;
71        }
72
73        $url = \sprintf($this->linkPattern, $handle);
74
75        $inlineContext->getContainer()->appendChild(new Link($url, '@' . $handle));
76
77        return true;
78    }
79
80    /**
81     * @return InlineMentionParser
82     */
83    public static function createTwitterHandleParser()
84    {
85        return new self('https://twitter.com/%s', '/^[A-Za-z0-9_]{1,15}(?!\w)/');
86    }
87
88    /**
89     * @return InlineMentionParser
90     */
91    public static function createGithubHandleParser()
92    {
93        // RegEx adapted from https://github.com/shinnn/github-username-regex/blob/master/index.js
94        return new self('https://www.github.com/%s', '/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)/');
95    }
96}
97