Skip to content

Commit 2dad0a9

Browse files
committed
Ignore long lines caused by i18n function arguments
Replacing the Generic.Files.LineLength sniff from PSR-2
1 parent 7658613 commit 2dad0a9

File tree

2 files changed

+256
-1
lines changed

2 files changed

+256
-1
lines changed
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
<?php declare(strict_types=1); # -*- coding: utf-8 -*-
2+
/*
3+
* This file is part of the php-coding-standards package.
4+
*
5+
* (c) Inpsyde GmbH
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* This file contains code from "PHP_CodeSniffer" repository
11+
* found at https://github.com/squizlabs/PHP_CodeSniffer
12+
* Copyright (c) 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
13+
* released under BSD license.
14+
*/
15+
16+
namespace Inpsyde\InpsydeCodingStandard\Sniffs\CodeQuality;
17+
18+
use PHP_CodeSniffer\Sniffs\Sniff;
19+
use PHP_CodeSniffer\Files\File;
20+
21+
/**
22+
* Modified version of the `LineLengthSniff` from "Generic" standard that
23+
* ignores long lines when they contain string
24+
*
25+
* @package Inpsyde\InpsydeCodingStandard\Sniffs\CodeQuality
26+
*/
27+
class LineLengthSniff implements Sniff
28+
{
29+
const I18N_FUNCTIONS = [
30+
'__',
31+
'_e',
32+
'_x',
33+
'_n',
34+
'_nx',
35+
'_ex',
36+
'_n_noop',
37+
'_nx_noop',
38+
'esc_html__',
39+
'esc_html_e',
40+
'esc_html_x',
41+
'esc_attr__',
42+
'esc_attr_e',
43+
'esc_attr_x',
44+
];
45+
46+
const IGNORE_TYPES = [
47+
T_WHITESPACE,
48+
T_OPEN_PARENTHESIS,
49+
T_COMMENT,
50+
T_DOC_COMMENT,
51+
T_DOC_COMMENT_CLOSE_TAG,
52+
T_DOC_COMMENT_OPEN_TAG,
53+
T_DOC_COMMENT_STAR,
54+
T_DOC_COMMENT_WHITESPACE,
55+
T_DOC_COMMENT_STRING,
56+
T_DOC_COMMENT_TAG,
57+
];
58+
59+
const STRING_TYPES = [
60+
T_CONSTANT_ENCAPSED_STRING,
61+
T_COMMENT,
62+
T_DOC_COMMENT_STRING,
63+
];
64+
65+
/**
66+
* The limit that the length of a line should not exceed.
67+
*
68+
* @var integer
69+
*/
70+
public $lineLimit = 120;
71+
72+
73+
/**
74+
* Returns an array of tokens this test wants to listen for.
75+
*
76+
* @return array
77+
*/
78+
public function register()
79+
{
80+
return [T_OPEN_TAG];
81+
}
82+
83+
/**
84+
* @inheritdoc
85+
*/
86+
public function process(File $phpcsFile, $stackPtr)
87+
{
88+
$tokens = $phpcsFile->getTokens();
89+
for ($i = 1; $i < $phpcsFile->numTokens; $i++) {
90+
if ($tokens[$i]['column'] === 1) {
91+
$this->checkLineLength($phpcsFile, $tokens, $i);
92+
}
93+
}
94+
95+
$this->checkLineLength($phpcsFile, $tokens, $i);
96+
97+
return ($phpcsFile->numTokens + 1);
98+
99+
}
100+
101+
/**
102+
* @param File $file
103+
* @param array $tokens
104+
* @param int $position
105+
*/
106+
protected function checkLineLength(File $file, array $tokens, int $position)
107+
{
108+
// The passed token is the first on the line.
109+
$position--;
110+
111+
if ($tokens[$position]['column'] === 1
112+
&& $tokens[$position]['length'] === 0
113+
) {
114+
// Blank line.
115+
return;
116+
}
117+
118+
if ($tokens[$position]['column'] !== 1
119+
&& $tokens[$position]['content'] === $file->eolChar
120+
) {
121+
$position--;
122+
}
123+
124+
$length = $tokens[$position]['column'] + $tokens[$position]['length'] - 1;
125+
126+
if ($length <= $this->lineLimit
127+
|| $this->shouldIgnoreLine($tokens, $file, $position)
128+
) {
129+
return;
130+
}
131+
132+
$file->addWarning(
133+
'Line exceeds %s characters; contains %s characters',
134+
$position,
135+
'TooLong',
136+
[$this->lineLimit, $length]
137+
);
138+
139+
}
140+
141+
/**
142+
* Don't warn for lines that exceeds limit, but either are part of
143+
* translations function first argument or cointain single words that alone
144+
* are longer that line limit (e.g. long URLs).
145+
*
146+
* @param array $tokens
147+
* @param File $file
148+
* @param int $position
149+
* @return bool
150+
*/
151+
private function shouldIgnoreLine(
152+
array $tokens,
153+
File $file,
154+
int $position
155+
): bool {
156+
157+
$line = $tokens[$position]['line'];
158+
$index = $position;
159+
160+
while ($index > 0) {
161+
if ($this->isI18nFunction($tokens, $index, $file)
162+
||$this->containLongWords($tokens, $index)
163+
) {
164+
return true;
165+
}
166+
if ($tokens[$index]['line'] !== $line) {
167+
break;
168+
}
169+
$index--;
170+
}
171+
172+
return false;
173+
}
174+
175+
/**
176+
* @param array $tokens
177+
* @param int $position
178+
* @return bool
179+
*/
180+
private function containLongWords(
181+
array $tokens,
182+
int $position
183+
): bool {
184+
185+
$string = $tokens[$position] ?? null;
186+
if (!$string
187+
|| !in_array($string['code'], self::STRING_TYPES, true)
188+
|| strlen($string['content']) < $this->lineLimit
189+
) {
190+
return false;
191+
}
192+
193+
$words = array_filter(preg_split('~[ ,.;:?!¿¡]~', $string['content']));
194+
foreach ($words as $word) {
195+
if (strlen($word) >= $this->lineLimit) {
196+
return true;
197+
}
198+
}
199+
200+
return false;
201+
}
202+
203+
/**
204+
* @param array $tokens
205+
* @param int $position
206+
* @param File $file
207+
* @return bool
208+
*/
209+
private function isI18nFunction(
210+
array $tokens,
211+
int $position,
212+
File $file
213+
): bool {
214+
215+
$string = $tokens[$position] ?? null;
216+
if (!$string
217+
|| $string['code'] !== T_CONSTANT_ENCAPSED_STRING
218+
|| strlen($string['content']) < $this->lineLimit
219+
) {
220+
return false;
221+
}
222+
223+
$previousPos = $file->findPrevious(
224+
self::IGNORE_TYPES,
225+
$position - 1,
226+
null,
227+
true,
228+
null,
229+
true
230+
);
231+
232+
$previous = $previousPos ? $tokens[$previousPos] ?? null : null;
233+
234+
if (!$previous
235+
|| $previous['code'] !== T_STRING
236+
|| !in_array($previous['content'], self::I18N_FUNCTIONS, true)
237+
) {
238+
return false;
239+
}
240+
241+
$next = $file->findNext(
242+
[T_WHITESPACE],
243+
$previousPos + 1,
244+
null,
245+
true,
246+
null,
247+
true
248+
);
249+
250+
return $tokens[$next]['code'] === T_OPEN_PARENTHESIS;
251+
}
252+
253+
}

Inpsyde/ruleset.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
PSR 2 Code style.
1616
See http://www.php-fig.org/psr/psr-2/
1717
-->
18-
<rule ref="PSR2"/>
18+
<rule ref="PSR2">
19+
<exclude name="Generic.Files.LineLength.TooLong"/>
20+
</rule>
1921

2022
<!--
2123
Some sanity in variables.

0 commit comments

Comments
 (0)