Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new Sniff to restrict line length in docblocks #171

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions BigBite/Docs/Commenting/DocCommentLineLengthStandard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<documentation title="Doc Comment Line Length">
<standard>
<![CDATA[
Block comments should not be longer than a set length (default 80 characters), and must not exceed an absolute length (default 100 characters).
]]>
</standard>
<standard>
<![CDATA[
Block comment line length should not exceed 80 characters.
]]>
</standard>
<code_comparison>
<code title="Valid: Comment line is shorter than 80 characters.">
<![CDATA[
/**
* <em>This is an example of a comment line that does not exceed 80 characters.</em>
*/
]]>
</code>
<code title="Invalid: Comment line is longer than 80 characters.">
<![CDATA[
/**
* <em>This is an example of a comment line that does exceed the soft maximum of 80 characters.</em>
*/
]]>
</code>
</code_comparison>
<standard>
<![CDATA[
Block comment line length must not exceed 100 characters.
]]>
</standard>
<code_comparison>
<code title="Valid: Comment line is longer than 80 characters, but shorter than 100.">
<![CDATA[
/**
* <em>This is an example of a comment line that does not exceed the maximum of 100 characters.</em>
*/
]]>
</code>
<code title="Invalid: Comment line is longer than 100 characters.">
<![CDATA[
/**
* <em>This is an example of a comment line that does exceed the hard maximum of 100 characters, which is a no-no.</em>
*/
]]>
</code>
</code_comparison>
</documentation>
159 changes: 159 additions & 0 deletions BigBite/Sniffs/Commenting/DocCommentLineLengthSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php
/**
* BigBite Coding Standards.
*
* @package BigBiteCS\BigBite
* @link https://github.com/bigbite/phpcs-config
* @license https://opensource.org/licenses/MIT MIT
*/

namespace BigBiteCS\BigBite\Sniffs\Commenting;

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

/**
* Restricts max line length in block comments
*/
final class DocCommentLineLengthSniff implements Sniff {

/**
* A list of tokenizers this sniff supports.
*
* @var array<int,string>
*/
public $supportedTokenizers = array(
'PHP',
);

/**
* The limit that the length of a line should not exceed.
*
* @var int
*/
public $lineLimit = 80;

/**
* The limit that the length of a line must not exceed.
*
* Set to zero (0) to disable.
*
* @var int
*/
public $absoluteLineLimit = 100;

/**
* Whether to include the indentation level in the calculation.
*
* @var bool
*/
public $includeIndentation = false;

/**
* Returns an array of tokens this test wants to listen for.
*
* @return array<int,string>
*/
public function register() {
return array( \T_DOC_COMMENT_OPEN_TAG );
}

/**
* Processes this test, when one of its tokens is encountered.
*
* @param \PHP_CodeSniffer\Files\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;
}

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

$empty = array(
\T_DOC_COMMENT_WHITESPACE,
\T_DOC_COMMENT_STAR,
);

$short = $phpcsFile->findNext( $empty, ( $stackPtr + 1 ), $commentEnd, true );
if ( false === $short ) {
// No content at all.
return;
}

if ( 1 === preg_match( '/^(Plugin|Theme)\s+Name:/i', $tokens[ $short ]['content'] ) ) {
// It's a WordPress plugin or theme, so disregard line length.
return;
}

for ( $i = ( $commentStart + 1 ); $i < $commentEnd; $i++ ) {
if ( \T_DOC_COMMENT_STRING !== $tokens[ $i ]['code'] ) {
continue;
}

$lineLength = $tokens[ $i ]['length'];
if ( true === $this->includeIndentation ) {
$lineLength = ( $tokens[ $i ]['column'] + $tokens[ $i ]['length'] - 1 );
}

// Record metrics.
if ( $lineLength <= $this->lineLimit ) {
$phpcsFile->recordMetric( $i, 'Line length', "{$this->lineLimit} or less" );
} elseif ( $lineLength <= $this->absoluteLineLimit ) {
$phpcsFile->recordMetric( $i, 'Line length', "{$this->absoluteLineLimit} or less" );
} else {
$phpcsFile->recordMetric( $i, 'Line length', "more than {$this->absoluteLineLimit}" );
}

// If this is a long comment, check if it can be broken up onto multiple lines.
// Some comments contain unbreakable strings like URLs and so it makes sense
// to ignore the line length in these cases if the URL would be longer than the max
// line length once you indent it to the correct level.
if ( $lineLength > $this->lineLimit ) {
$oldLength = strlen( $tokens[ $i ]['content'] );
$newLength = strlen( ltrim( $tokens[ $i ]['content'], "/#\t " ) );
$indent = ( ( $tokens[ $i ]['column'] - 1 ) + ( $oldLength - $newLength ) );

$nonBreakingLength = $tokens[ $i ]['length'];

$space = strrpos( $tokens[ $i ]['content'], ' ' );
if ( false !== $space ) {
$nonBreakingLength -= ( $space + 1 );
}

if ( ( $nonBreakingLength + $indent ) > $this->lineLimit ) {
return;
}
}

if ( $this->absoluteLineLimit > 0 && $lineLength > $this->absoluteLineLimit ) {
$data = array(
$this->absoluteLineLimit,
$lineLength,
);

$error = 'Line exceeds maximum limit of %s characters; contains %s characters';
$phpcsFile->addError( $error, $i, 'MaxExceeded', $data );
} elseif ( $lineLength > $this->lineLimit ) {
$data = array(
$this->lineLimit,
$lineLength,
);

$warning = 'Line exceeds %s characters; contains %s characters';
$phpcsFile->addWarning( $warning, $i, 'TooLong', $data );
}
}
}
}
35 changes: 35 additions & 0 deletions BigBite/Tests/Commenting/DocCommentLineLengthUnitTest.1.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/**
* This is a comment line that exceeds 80 characters, and should therefore trigger a warning.
*/

/**
* This is a comment line that exceeds the maximum 100 characters, and should therefore trigger an error.
*/

/**
* This-comment-exceeds-80-characters-but-is-non-breakable-text-so-should-not-trigger-a-warning.
*/

/**
* This-comment-line-exceeds-the-maximum-100-characters-but-is-non-breakable-text-so-should-not-trigger-an-error.
*/

/**
* Plugin Name: Line lengths
* Description: WordPress plugin/theme comment line lengths are excluded from this sniff.
*/

/**
* Theme Name: Line lengths
* Description: WordPress plugin/theme comment line lengths are excluded from this sniff, both soft limit and hard limit.
*/

/**
* This is a comment line that should not trigger a warning, nor an error.
*/

/**
* This is a comment line that should not trigger a warning, nor an error.
*/
37 changes: 37 additions & 0 deletions BigBite/Tests/Commenting/DocCommentLineLengthUnitTest.1.inc.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/**
* This is a comment line that exceeds 80 characters,
* and should therefore trigger a warning.
*/

/**
* This is a comment line that exceeds the maximum 100 characters,
* and should therefore trigger an error.
*/

/**
* This-comment-exceeds-80-characters-but-is-non-breakable-text-so-should-not-trigger-a-warning.
*/

/**
* This-comment-line-exceeds-the-maximum-100-characters-but-is-non-breakable-text-so-should-not-trigger-an-error.
*/

/**
* Plugin Name: Line lengths
* Description: WordPress plugin/theme comment line lengths are excluded from this sniff.
*/

/**
* Theme Name: Line lengths
* Description: WordPress plugin/theme comment line lengths are excluded from this sniff, both soft limit and hard limit.
*/

/**
* This is a comment line that should not trigger a warning, nor an error.
*/

/**
* This is a comment line that should not trigger a warning, nor an error.
*/
19 changes: 19 additions & 0 deletions BigBite/Tests/Commenting/DocCommentLineLengthUnitTest.2.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

// phpcs:set BigBite.Commenting.DocCommentLineLength lineLimit 120
// phpcs:set BigBite.Commenting.DocCommentLineLength absoluteLineLimit 150

/**
* This is a comment line that exceeds the default of 80 characters, but is shorter than the configured 120 characters.
*/

/**
* This is a comment line that exceeds the default maximum of 100 characters, but is shorter than the configured 150. It should trigger a warning.
*/

/**
* This is a comment line that exceeds the default maximum of 100 characters, and is longer than the configured maximum of 150 characters, so should trigger an error.
*/

// phpcs:set BigBite.Commenting.DocCommentLineLength lineLimit 80
// phpcs:set BigBite.Commenting.DocCommentLineLength absoluteLineLimit 100
15 changes: 15 additions & 0 deletions BigBite/Tests/Commenting/DocCommentLineLengthUnitTest.3.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

// phpcs:set BigBite.Commenting.DocCommentLineLength absoluteLineLimit 90
// phpcs:set BigBite.Commenting.DocCommentLineLength includeIndentation true

/**
* This is a comment line that should trigger a warning.
*/

/**
* This is a comment line that should trigger an error due to this config setting.
*/

// phpcs:set BigBite.Commenting.DocCommentLineLength absoluteLineLimit 90
// phpcs:set BigBite.Commenting.DocCommentLineLength includeIndentation false
Loading