Completed
Push — master ( 3785a9...cbdf2a )
by Josh
16:27
created

Regexp::getNamedCapturesExpressions()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 10
cts 10
cp 1
rs 9.2728
c 0
b 0
f 0
cc 5
nc 4
nop 1
crap 5
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2019 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Configurator\Items;
9
10
use InvalidArgumentException;
11
use s9e\TextFormatter\Configurator\ConfigProvider;
12
use s9e\TextFormatter\Configurator\FilterableConfigValue;
13
use s9e\TextFormatter\Configurator\Helpers\RegexpParser;
14
use s9e\TextFormatter\Configurator\JavaScript\Code;
15
use s9e\TextFormatter\Configurator\JavaScript\RegexpConvertor;
16
17
class Regexp implements ConfigProvider, FilterableConfigValue
18
{
19
	/**
20
	* @var bool Whether this regexp should have the global flag set in JavaScript
21
	*/
22
	protected $isGlobal;
23
24
	/**
25
	* @var string JavaScript regexp, with delimiters and modifiers, e.g. "/foo/i"
26
	*/
27
	protected $jsRegexp;
28
29
	/**
30
	* @var string PCRE regexp, with delimiters and modifiers, e.g. "/foo/i"
31
	*/
32
	protected $regexp;
33
34
	/**
35
	* Constructor
36
	*
37
	* @param  string $regexp PCRE regexp, with delimiters and modifiers, e.g. "/foo/i"
38
	*/
39 13
	public function __construct($regexp, $isGlobal = false)
40
	{
41 13
		if (@preg_match($regexp, '') === false)
42
		{
43 1
			throw new InvalidArgumentException('Invalid regular expression ' . var_export($regexp, true));
44
		}
45
46 12
		$this->regexp   = $regexp;
47 12
		$this->isGlobal = $isGlobal;
48 12
	}
49
50
	/**
51
	* Return this regexp as a string
52
	*
53
	* @return string
54
	*/
55 2
	public function __toString()
56
	{
57 2
		return $this->regexp;
58
	}
59
60
	/**
61
	* {@inheritdoc}
62
	*/
63 1
	public function asConfig()
64
	{
65 1
		return $this;
66
	}
67
68
	/**
69
	* {@inheritdoc}
70
	*/
71 2
	public function filterConfig($target)
72
	{
73 2
		return ($target === 'JS') ? new Code($this->getJS()) : (string) $this;
74
	}
75
76
	/**
77
	* Return the name of each capture in this regexp
78
	*
79
	* @return string[]
80
	*/
81 1
	public function getCaptureNames()
82
	{
83 1
		return RegexpParser::getCaptureNames($this->regexp);
84
	}
85
86
	/**
87
	* Return this regexp's JavaScript representation
88
	*
89
	* @return string
90
	*/
91 4
	public function getJS()
92
	{
93 4
		if (!isset($this->jsRegexp))
94
		{
95 3
			$this->jsRegexp = RegexpConvertor::toJS($this->regexp, $this->isGlobal);
96
		}
97
98 4
		return $this->jsRegexp;
99
	}
100
101
	/**
102
	* Return all the named captures with a standalone regexp that matches them
103
	*
104
	* @return array Array of [capture name => regexp]
105
	*/
106 3
	public function getNamedCaptures()
107
	{
108 3
		$captures   = [];
109 3
		$regexpInfo = RegexpParser::parse($this->regexp);
110
111
		// Prepare the start/end of the regexp and ensure that we use the D modifier
112 3
		$start = $regexpInfo['delimiter'] . '^';
113 3
		$end   = '$' . $regexpInfo['delimiter'] . $regexpInfo['modifiers'];
114 3
		if (strpos($regexpInfo['modifiers'], 'D') === false)
115
		{
116 2
			$end .= 'D';
117
		}
118
119 3
		foreach ($this->getNamedCapturesExpressions($regexpInfo['tokens']) as $name => $expr)
120
		{
121 3
			$captures[$name] = $start . $expr . $end;
122
		}
123
124 3
		return $captures;
125
	}
126
127
	/**
128
	* Return the expression used in each named capture
129
	*
130
	* @param  array[] $tokens
131
	* @return array
132
	*/
133 3
	protected function getNamedCapturesExpressions(array $tokens)
134
	{
135 3
		$exprs = [];
136 3
		foreach ($tokens as $token)
137
		{
138 3
			if ($token['type'] !== 'capturingSubpatternStart' || !isset($token['name']))
139
			{
140 3
				continue;
141
			}
142
143 3
			$expr = $token['content'];
144 3
			if (strpos($expr, '|') !== false)
145
			{
146 1
				$expr = '(?:' . $expr . ')';
147
			}
148
149 3
			$exprs[$token['name']] = $expr;
150
		}
151
152 3
		return $exprs;
153
	}
154
155
	/**
156
	* Set this regexp's JavaScript representation
157
	*
158
	* @param  string $jsRegexp
159
	* @return void
160
	*/
161 1
	public function setJS($jsRegexp)
162
	{
163 1
		$this->jsRegexp = $jsRegexp;
164
	}
165
}