Completed
Push — master ( 9d183f...fa9903 )
by Josh
26:00
created

Regexp::toJS()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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