Skip to content

Commit

Permalink
Merge pull request #55 from VincentLanglet/comment
Browse files Browse the repository at this point in the history
✨ Add comment rule
  • Loading branch information
VincentLanglet authored May 20, 2019
2 parents 46ece10 + 00d27c9 commit 4fced60
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 12 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Symfony Custom PHP CodeSniffer Coding Standard
# Symfony Custom Coding Standard

[![MIT Licence](https://badges.frapsoft.com/os/mit/mit.png?v=103)](https://opensource.org/licenses/mit-license.php)
[![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)
Expand All @@ -7,5 +7,5 @@ Customized coding standards for Symfony projects.

Documentation
-------------
* [Coding Standard](docs/standards.md)
* [PHP Coding Standard](docs/standards.md)
* [Installation](docs/installation.md)
3 changes: 0 additions & 3 deletions SymfonyCustom/Sniffs/Commenting/ClassCommentSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
* Verifies that :
* <ul>
* <li>A doc comment exists.</li>
* <li>There is a blank newline after the short description.</li>
* <li>There is a blank newline between the long and short description.</li>
* <li>There is a blank newline between the long description and tags.</li>
* <li>Check the order of the tags.</li>
* <li>Check the indentation of each tag.</li>
* <li>Check required and optional tags and the format of their content.</li>
Expand Down
152 changes: 152 additions & 0 deletions SymfonyCustom/Sniffs/Commenting/DocCommentSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php

namespace SymfonyCustom\Sniffs\Commenting;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;

/**
* Ensures doc blocks follow basic formatting.
*/
class DocCommentSniff implements Sniff
{
/**
* A list of tokenizers this sniff supports.
*
* @var array
*/
public $supportedTokenizers = [
'PHP',
'JS',
];

/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return [T_DOC_COMMENT_OPEN_TAG];
}

/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();

if (false === isset($tokens[$stackPtr]['comment_closer'])
|| ('' === $tokens[$tokens[$stackPtr]['comment_closer']]['content']
&& ($phpcsFile->numTokens - 1) === $tokens[$stackPtr]['comment_closer'])
) {
// Don't process an unfinished comment during live coding.
return;
}

$commentEnd = $tokens[$stackPtr]['comment_closer'];

$empty = [
T_DOC_COMMENT_WHITESPACE,
T_DOC_COMMENT_STAR,
];

$short = $phpcsFile->findNext($empty, ($stackPtr + 1), $commentEnd, true);
if (false === $short) {
// No content at all.
$error = 'Doc comment is empty';
$phpcsFile->addError($error, $stackPtr, 'Empty');

return;
}

$isSingleLine = $tokens[$stackPtr]['line'] === $tokens[$commentEnd]['line'];

// The first line of the comment should just be the /** code.
if (!$isSingleLine && $tokens[$short]['line'] === $tokens[$stackPtr]['line']) {
$error = 'The open comment tag must be the only content on the line';
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentAfterOpen');
if (true === $fix) {
$phpcsFile->fixer->beginChangeset();
for ($i = ($stackPtr + 1); $i < $short; $i++) {
$phpcsFile->fixer->replaceToken($i, '');
}
$phpcsFile->fixer->addNewline($stackPtr);
$phpcsFile->fixer->replaceToken(
$short,
ltrim($tokens[$short]['content'])
);
$phpcsFile->fixer->addContentBefore(
$short,
str_repeat(' ', $tokens[$stackPtr]['column']).'* '
);
$phpcsFile->fixer->endChangeset();
}
}

// Check for additional blank lines at the beginning of the comment.
if ($tokens[$stackPtr]['line'] < ($tokens[$short]['line'] - 1)) {
$error = 'Additional blank lines found at beginning of doc comment';
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore');
if (true === $fix) {
$phpcsFile->fixer->beginChangeset();
for ($i = ($stackPtr + 1); $i < $short; $i++) {
if ($tokens[($i + 1)]['line'] === $tokens[$short]['line']) {
break;
}

$phpcsFile->fixer->replaceToken($i, '');
}

$phpcsFile->fixer->endChangeset();
}
}

// The last line of the comment should just be the */ code.
$prev = $phpcsFile->findPrevious($empty, ($commentEnd - 1), $stackPtr, true);
if (!$isSingleLine && $tokens[$prev]['line'] === $tokens[$commentEnd]['line']) {
$error = 'The close comment tag must be the only content on the line';
$fix = $phpcsFile->addFixableError($error, $commentEnd, 'ContentBeforeClose');
if (true === $fix) {
$phpcsFile->fixer->beginChangeset();
for ($i = ($prev + 1); $i < $commentEnd; $i++) {
$phpcsFile->fixer->replaceToken($i, '');
}
$phpcsFile->fixer->replaceToken(
$commentEnd - 1,
rtrim($tokens[$commentEnd - 1]['content'])
);
$phpcsFile->fixer->addContentBefore(
$commentEnd,
str_repeat(' ', $tokens[$stackPtr]['column'])
);
$phpcsFile->fixer->addNewlineBefore($commentEnd);
$phpcsFile->fixer->endChangeset();
}
}

// Check for additional blank lines at the end of the comment.
if ($tokens[$prev]['line'] < ($tokens[$commentEnd]['line'] - 1)) {
$error = 'Additional blank lines found at end of doc comment';
$fix = $phpcsFile->addFixableError($error, $commentEnd, 'SpacingAfter');
if (true === $fix) {
$phpcsFile->fixer->beginChangeset();
for ($i = ($prev + 1); $i < $commentEnd; $i++) {
if ($tokens[($i + 1)]['line'] === $tokens[$commentEnd]['line']) {
break;
}

$phpcsFile->fixer->replaceToken($i, '');
}

$phpcsFile->fixer->endChangeset();
}
}
}
}
10 changes: 5 additions & 5 deletions SymfonyCustom/Sniffs/Commenting/VariableCommentSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,14 @@ public function processMemberVar(File $phpcsFile, $stackPtr)
}

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

if (true === $fix) {
$newContent = array_filter($content, function ($value) use ($tokens, $stackPtr) {
return $tokens[$stackPtr]['content'] !== $value;
});
$phpcsFile->fixer->replaceToken($string, implode(' ', $newContent));
}
}
Expand Down
35 changes: 35 additions & 0 deletions SymfonyCustom/Tests/Commenting/DocCommentUnitTest.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

class Test
{
/**
* Short description.
*/

/**
*
*/

/**
*/

/** */

/**
*
* Short description.
*/

/**
* Short description.
*
*/

/** Short description.
*/

/** Short description. */

/**
* Short description. */
}
35 changes: 35 additions & 0 deletions SymfonyCustom/Tests/Commenting/DocCommentUnitTest.inc.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

class Test
{
/**
* Short description.
*/

/**
*
*/

/**
*/

/** */

/**
* Short description.
*/

/**
* Short description.
*/

/**
* Short description.
*/

/** Short description. */

/**
* Short description.
*/
}
47 changes: 47 additions & 0 deletions SymfonyCustom/Tests/Commenting/DocCommentUnitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace SymfonyCustom\Tests\Commenting;

use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest;

/**
* Unit test class for the DocComment sniff.
*
* @group SymfonyCustom
*/
class DocCommentUnitTest extends AbstractSniffUnitTest
{
/**
* Returns the lines where errors should occur.
*
* The key of the array should represent the line number and the value
* should represent the number of errors that should occur on that line.
*
* @return array<int, int>
*/
public function getErrorList()
{
return [
9 => 1,
13 => 1,
16 => 1,
18 => 1,
26 => 1,
28 => 1,
34 => 1,
];
}

/**
* Returns the lines where warnings should occur.
*
* The key of the array should represent the line number and the value
* should represent the number of warnings that should occur on that line.
*
* @return array(int => int)
*/
protected function getWarningList()
{
return [];
}
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"coding standard",
"phpcs"
],
"homepage": "https://github.com/VincentLanglet/Symfony-coding-standard",
"homepage": "https://github.com/VincentLanglet/Symfony-custom-coding-standard",
"license": "MIT",
"authors": [
{
Expand Down
2 changes: 1 addition & 1 deletion docs/standards.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Coding Standard Rules
# PHP CS Coding Standard Rules
## From PSR2

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

0 comments on commit 4fced60

Please sign in to comment.