Completed
Push — master ( fc1df1...d515dd )
by Josh
01:55
created

RemoveComments::removeDocBlocks()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 9
cts 9
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 3
nop 0
crap 4
1
<?php
2
3
/**
4
* @package   s9e\SourceOptimizer
5
* @copyright Copyright (c) 2014-2017 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\SourceOptimizer\Passes;
9
10
use s9e\SourceOptimizer\Helper;
11
use s9e\SourceOptimizer\Pass;
12
use s9e\SourceOptimizer\TokenStream;
13
14
class RemoveComments extends Pass
15
{
16
	/**
17
	* @var string[] List of annotations to preserve
18
	*/
19
	public $preserveAnnotations = [
20
		'license'
21
	];
22
23
	/**
24
	* @var bool Whether to remove DocBlock comments
25
	*/
26
	public $removeDocBlocks = true;
27
28
	/**
29
	* @var bool Whether to remove "C style" comments
30
	*/
31
	public $removeMultiLineComments = true;
32
33
	/**
34
	* @var bool Whether to remove "one-line" comments
35
	*/
36
	public $removeSingleLineComments = true;
37
38
	/**
39
	* @var TokenStream Token stream of the source being processed
40
	*/
41
	protected $stream;
42
43
	/**
44
	* {@inheritdoc}
45
	*/
46 13
	public function optimize(TokenStream $stream)
47
	{
48 13
		$this->stream = $stream;
49 13
		if ($this->removeDocBlocks)
50
		{
51 12
			$this->removeDocBlocks();
52
		}
53 13
		if ($this->removeMultiLineComments || $this->removeSingleLineComments)
54
		{
55 13
			$this->removeComments();
56
		}
57 13
		Helper::mergeWhitespace($stream);
58 13
	}
59
60
	/**
61
	* Generate a regexp that matches preserved annotations
62
	*
63
	* @return string
64
	*/
65 12
	protected function getRegexp()
66
	{
67 12
		if (empty($this->preserveAnnotations))
68
		{
69
			return '((?!))';
70
		}
71
72 12
		return '(@(?:' . implode('|', $this->preserveAnnotations) . '))';
73
	}
74
75
	/**
76
	* Remove all docblocks tokens from given stream
77
	*
78
	* @return void
79
	*/
80 12
	protected function removeDocBlocks()
81
	{
82 12
		$regexp = $this->getRegexp();
83 12
		$this->stream->reset();
84 12
		while ($this->stream->skipTo(T_DOC_COMMENT))
85
		{
86 3
			$docblock = $this->stream->currentText();
87 3
			if (strpos($docblock, '@') !== false && preg_match($regexp, $docblock))
88
			{
89 2
				continue;
90
			}
91
92 1
			$this->removeComment();
93
		}
94 12
	}
95
96
	/**
97
	* Remove current comment token from given stream
98
	*
99
	* @return void
100
	*/
101 8
	protected function removeComment()
102
	{
103 8
		$offset = $this->stream->key();
104 8
		$this->stream->previous();
105 8
		if ($this->stream->is(T_WHITESPACE))
106
		{
107 6
			$ws = preg_replace('(\\n[ \\t]*$)', '', $this->stream->currentText());
108 6
			if ($ws === '')
109
			{
110 6
				$this->stream->remove();
111
			}
112
			else
113
			{
114
				$this->stream->replace([T_WHITESPACE, $ws]);
115
			}
116
		}
117
118 8
		$this->stream->seek($offset);
119 8
		if ($this->stream->canRemoveCurrentToken())
120
		{
121 7
			$this->stream->remove();
122
		}
123
		else
124
		{
125 1
			$this->stream->replace([T_WHITESPACE, ' ']);
126
		}
127 8
	}
128
129
	/**
130
	* Remove single-line and/or multi-line comments from given stream
131
	*
132
	* @return void
133
	*/
134 13
	protected function removeComments()
135
	{
136 13
		$this->stream->reset();
137 13
		while ($this->stream->skipTo(T_COMMENT))
138
		{
139 9
			$comment = $this->stream->currentText();
140 9
			if ($comment[1] === '/' && !$this->removeSingleLineComments)
141
			{
142 1
				continue;
143
			}
144 8
			if ($comment[1] === '*' && !$this->removeMultiLineComments)
145
			{
146 1
				continue;
147
			}
148
149 7
			$this->removeComment();
150
		}
151
	}
152
}