Skip to content

Commit 4fced60

Browse files
Merge pull request #55 from VincentLanglet/comment
✨ Add comment rule
2 parents 46ece10 + 00d27c9 commit 4fced60

9 files changed

+278
-12
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Symfony Custom PHP CodeSniffer Coding Standard
1+
# Symfony Custom Coding Standard
22

33
[![MIT Licence](https://badges.frapsoft.com/os/mit/mit.png?v=103)](https://opensource.org/licenses/mit-license.php)
44
[![CircleCI](https://circleci.com/gh/VincentLanglet/Symfony-custom-coding-standard.svg?style=shield&circle-token=04bcfbcceb34f9644561c0a9ef27e935ff467705)](https://circleci.com/gh/VincentLanglet/Symfony-custom-coding-standard)
@@ -7,5 +7,5 @@ Customized coding standards for Symfony projects.
77

88
Documentation
99
-------------
10-
* [Coding Standard](docs/standards.md)
10+
* [PHP Coding Standard](docs/standards.md)
1111
* [Installation](docs/installation.md)

SymfonyCustom/Sniffs/Commenting/ClassCommentSniff.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
* Verifies that :
1111
* <ul>
1212
* <li>A doc comment exists.</li>
13-
* <li>There is a blank newline after the short description.</li>
14-
* <li>There is a blank newline between the long and short description.</li>
15-
* <li>There is a blank newline between the long description and tags.</li>
1613
* <li>Check the order of the tags.</li>
1714
* <li>Check the indentation of each tag.</li>
1815
* <li>Check required and optional tags and the format of their content.</li>
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<?php
2+
3+
namespace SymfonyCustom\Sniffs\Commenting;
4+
5+
use PHP_CodeSniffer\Files\File;
6+
use PHP_CodeSniffer\Sniffs\Sniff;
7+
8+
/**
9+
* Ensures doc blocks follow basic formatting.
10+
*/
11+
class DocCommentSniff implements Sniff
12+
{
13+
/**
14+
* A list of tokenizers this sniff supports.
15+
*
16+
* @var array
17+
*/
18+
public $supportedTokenizers = [
19+
'PHP',
20+
'JS',
21+
];
22+
23+
/**
24+
* Returns an array of tokens this test wants to listen for.
25+
*
26+
* @return array
27+
*/
28+
public function register()
29+
{
30+
return [T_DOC_COMMENT_OPEN_TAG];
31+
}
32+
33+
/**
34+
* Processes this test, when one of its tokens is encountered.
35+
*
36+
* @param File $phpcsFile The file being scanned.
37+
* @param int $stackPtr The position of the current token in the stack passed in $tokens.
38+
*
39+
* @return void
40+
*/
41+
public function process(File $phpcsFile, $stackPtr)
42+
{
43+
$tokens = $phpcsFile->getTokens();
44+
45+
if (false === isset($tokens[$stackPtr]['comment_closer'])
46+
|| ('' === $tokens[$tokens[$stackPtr]['comment_closer']]['content']
47+
&& ($phpcsFile->numTokens - 1) === $tokens[$stackPtr]['comment_closer'])
48+
) {
49+
// Don't process an unfinished comment during live coding.
50+
return;
51+
}
52+
53+
$commentEnd = $tokens[$stackPtr]['comment_closer'];
54+
55+
$empty = [
56+
T_DOC_COMMENT_WHITESPACE,
57+
T_DOC_COMMENT_STAR,
58+
];
59+
60+
$short = $phpcsFile->findNext($empty, ($stackPtr + 1), $commentEnd, true);
61+
if (false === $short) {
62+
// No content at all.
63+
$error = 'Doc comment is empty';
64+
$phpcsFile->addError($error, $stackPtr, 'Empty');
65+
66+
return;
67+
}
68+
69+
$isSingleLine = $tokens[$stackPtr]['line'] === $tokens[$commentEnd]['line'];
70+
71+
// The first line of the comment should just be the /** code.
72+
if (!$isSingleLine && $tokens[$short]['line'] === $tokens[$stackPtr]['line']) {
73+
$error = 'The open comment tag must be the only content on the line';
74+
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentAfterOpen');
75+
if (true === $fix) {
76+
$phpcsFile->fixer->beginChangeset();
77+
for ($i = ($stackPtr + 1); $i < $short; $i++) {
78+
$phpcsFile->fixer->replaceToken($i, '');
79+
}
80+
$phpcsFile->fixer->addNewline($stackPtr);
81+
$phpcsFile->fixer->replaceToken(
82+
$short,
83+
ltrim($tokens[$short]['content'])
84+
);
85+
$phpcsFile->fixer->addContentBefore(
86+
$short,
87+
str_repeat(' ', $tokens[$stackPtr]['column']).'* '
88+
);
89+
$phpcsFile->fixer->endChangeset();
90+
}
91+
}
92+
93+
// Check for additional blank lines at the beginning of the comment.
94+
if ($tokens[$stackPtr]['line'] < ($tokens[$short]['line'] - 1)) {
95+
$error = 'Additional blank lines found at beginning of doc comment';
96+
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore');
97+
if (true === $fix) {
98+
$phpcsFile->fixer->beginChangeset();
99+
for ($i = ($stackPtr + 1); $i < $short; $i++) {
100+
if ($tokens[($i + 1)]['line'] === $tokens[$short]['line']) {
101+
break;
102+
}
103+
104+
$phpcsFile->fixer->replaceToken($i, '');
105+
}
106+
107+
$phpcsFile->fixer->endChangeset();
108+
}
109+
}
110+
111+
// The last line of the comment should just be the */ code.
112+
$prev = $phpcsFile->findPrevious($empty, ($commentEnd - 1), $stackPtr, true);
113+
if (!$isSingleLine && $tokens[$prev]['line'] === $tokens[$commentEnd]['line']) {
114+
$error = 'The close comment tag must be the only content on the line';
115+
$fix = $phpcsFile->addFixableError($error, $commentEnd, 'ContentBeforeClose');
116+
if (true === $fix) {
117+
$phpcsFile->fixer->beginChangeset();
118+
for ($i = ($prev + 1); $i < $commentEnd; $i++) {
119+
$phpcsFile->fixer->replaceToken($i, '');
120+
}
121+
$phpcsFile->fixer->replaceToken(
122+
$commentEnd - 1,
123+
rtrim($tokens[$commentEnd - 1]['content'])
124+
);
125+
$phpcsFile->fixer->addContentBefore(
126+
$commentEnd,
127+
str_repeat(' ', $tokens[$stackPtr]['column'])
128+
);
129+
$phpcsFile->fixer->addNewlineBefore($commentEnd);
130+
$phpcsFile->fixer->endChangeset();
131+
}
132+
}
133+
134+
// Check for additional blank lines at the end of the comment.
135+
if ($tokens[$prev]['line'] < ($tokens[$commentEnd]['line'] - 1)) {
136+
$error = 'Additional blank lines found at end of doc comment';
137+
$fix = $phpcsFile->addFixableError($error, $commentEnd, 'SpacingAfter');
138+
if (true === $fix) {
139+
$phpcsFile->fixer->beginChangeset();
140+
for ($i = ($prev + 1); $i < $commentEnd; $i++) {
141+
if ($tokens[($i + 1)]['line'] === $tokens[$commentEnd]['line']) {
142+
break;
143+
}
144+
145+
$phpcsFile->fixer->replaceToken($i, '');
146+
}
147+
148+
$phpcsFile->fixer->endChangeset();
149+
}
150+
}
151+
}
152+
}

SymfonyCustom/Sniffs/Commenting/VariableCommentSniff.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,14 @@ public function processMemberVar(File $phpcsFile, $stackPtr)
9595
}
9696

9797
$content = explode(' ', $tokens[$string]['content']);
98-
if (in_array($tokens[$stackPtr]['content'], $content)) {
99-
$error = '@var annotations should not contain the variable name';
98+
$newContent = array_filter($content, function ($value) use ($tokens, $stackPtr) {
99+
return 0 === preg_match('/^\$/', $value);
100+
});
101+
if (count($newContent) < count($content)) {
102+
$error = '@var annotations should not contain variable name';
100103
$fix = $phpcsFile->addFixableError($error, $foundVar, 'NamedVar');
101104

102105
if (true === $fix) {
103-
$newContent = array_filter($content, function ($value) use ($tokens, $stackPtr) {
104-
return $tokens[$stackPtr]['content'] !== $value;
105-
});
106106
$phpcsFile->fixer->replaceToken($string, implode(' ', $newContent));
107107
}
108108
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
class Test
4+
{
5+
/**
6+
* Short description.
7+
*/
8+
9+
/**
10+
*
11+
*/
12+
13+
/**
14+
*/
15+
16+
/** */
17+
18+
/**
19+
*
20+
* Short description.
21+
*/
22+
23+
/**
24+
* Short description.
25+
*
26+
*/
27+
28+
/** Short description.
29+
*/
30+
31+
/** Short description. */
32+
33+
/**
34+
* Short description. */
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
class Test
4+
{
5+
/**
6+
* Short description.
7+
*/
8+
9+
/**
10+
*
11+
*/
12+
13+
/**
14+
*/
15+
16+
/** */
17+
18+
/**
19+
* Short description.
20+
*/
21+
22+
/**
23+
* Short description.
24+
*/
25+
26+
/**
27+
* Short description.
28+
*/
29+
30+
/** Short description. */
31+
32+
/**
33+
* Short description.
34+
*/
35+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace SymfonyCustom\Tests\Commenting;
4+
5+
use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest;
6+
7+
/**
8+
* Unit test class for the DocComment sniff.
9+
*
10+
* @group SymfonyCustom
11+
*/
12+
class DocCommentUnitTest extends AbstractSniffUnitTest
13+
{
14+
/**
15+
* Returns the lines where errors should occur.
16+
*
17+
* The key of the array should represent the line number and the value
18+
* should represent the number of errors that should occur on that line.
19+
*
20+
* @return array<int, int>
21+
*/
22+
public function getErrorList()
23+
{
24+
return [
25+
9 => 1,
26+
13 => 1,
27+
16 => 1,
28+
18 => 1,
29+
26 => 1,
30+
28 => 1,
31+
34 => 1,
32+
];
33+
}
34+
35+
/**
36+
* Returns the lines where warnings should occur.
37+
*
38+
* The key of the array should represent the line number and the value
39+
* should represent the number of warnings that should occur on that line.
40+
*
41+
* @return array(int => int)
42+
*/
43+
protected function getWarningList()
44+
{
45+
return [];
46+
}
47+
}

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"coding standard",
88
"phpcs"
99
],
10-
"homepage": "https://github.com/VincentLanglet/Symfony-coding-standard",
10+
"homepage": "https://github.com/VincentLanglet/Symfony-custom-coding-standard",
1111
"license": "MIT",
1212
"authors": [
1313
{

docs/standards.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Coding Standard Rules
1+
# PHP CS Coding Standard Rules
22
## From PSR2
33

44
We imported the [PSR2 Standard](./standards/psr2.md) with these overrides:

0 commit comments

Comments
 (0)