Skip to content

Commit

Permalink
Add MultipleEmptyLinesSniff
Browse files Browse the repository at this point in the history
  • Loading branch information
mmoll committed Aug 30, 2021
1 parent f50b15e commit 5f63628
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 3 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [8.0.0] -
### Added
- Add MO4.WhiteSpace.ConstantSpacing
- Add `MO4.WhiteSpace.ConstantSpacing`
- Add `MO4.WhiteSpace.MultipleEmptyLinesSniff`
### Changed
- refactored tests

Expand Down
97 changes: 97 additions & 0 deletions MO4/Sniffs/WhiteSpace/MultipleEmptyLinesSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

/**
*
* Check multiple consecutive newlines in a file.
* Source: MediaWiki. I didn't want to add dependency to whole package (because of only one sniff).
*
* @link https://github.com/wikimedia/mediawiki-tools-codesniffer/blob/272835d/MediaWiki/Sniffs/WhiteSpace/MultipleEmptyLinesSniff.php
*/

namespace MO4\Sniffs\WhiteSpace;

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

class MultipleEmptyLinesSniff implements Sniff
{
/**
* Registers the tokens that this sniff wants to listen for.
*
* @return array<int, int>
*
* @see Tokens.php
*/
public function register(): array
{
return [
// Assume most comments end with a newline
T_COMMENT,
// Assume all <?php open tags end with a newline
T_OPEN_TAG,
T_WHITESPACE,
];
}

/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint
*
* @param File $phpcsFile
* @param int $stackPtr The current token index.
*
* @return void|int
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();

// This sniff intentionally doesn't care about whitespace at the end of the file
if (!isset($tokens[$stackPtr + 3])
|| $tokens[$stackPtr + 2]['line'] === $tokens[$stackPtr + 3]['line']
) {
return $stackPtr + 3;
}

if ($tokens[$stackPtr + 1]['line'] === $tokens[$stackPtr + 2]['line']) {
return $stackPtr + 2;
}

// Finally, check the assumption the current token is or ends with a newline
if ($tokens[$stackPtr]['line'] === $tokens[$stackPtr + 1]['line']) {
return;
}

// Search for the next non-newline token
$next = $stackPtr + 1;

while (isset($tokens[$next + 1]) &&
$tokens[$next]['code'] === T_WHITESPACE &&
$tokens[$next]['line'] !== $tokens[$next + 1]['line']
) {
$next++;
}

$count = $next - $stackPtr - 1;

if ($count > 1
&& $phpcsFile->addFixableError(
'Multiple empty lines should not exist in a row; found %s consecutive empty lines',
$stackPtr + 1,
'MultipleEmptyLines',
[$count]
)
) {
$phpcsFile->fixer->beginChangeset();

// Remove all newlines except the first two, i.e. keep one empty line
for ($i = $stackPtr + 2; $i < $next; $i++) {
$phpcsFile->fixer->replaceToken($i, '');
}

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

// Don't check the current sequence a second time
return $next;
}
}
48 changes: 48 additions & 0 deletions MO4/Tests/WhiteSpace/MultipleEmptyLinesUnitTest.fail.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php


/**
* license header etc.
*/

/**
* Failed examples.
* @return void
*/
function wfFailedExamples() {
$a = 1;






$b = 2;


// Comment




// Comment 2


// Comment 3

/* Comment 4 */

# Comment 5

$c = 3;
}

/**
* Passed examples.
* @return void
*/
function wfPassedExamples() {
$a = 1;

$b = 2;
}
37 changes: 37 additions & 0 deletions MO4/Tests/WhiteSpace/MultipleEmptyLinesUnitTest.fail.inc.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/**
* license header etc.
*/

/**
* Failed examples.
* @return void
*/
function wfFailedExamples() {
$a = 1;

$b = 2;

// Comment

// Comment 2

// Comment 3

/* Comment 4 */

# Comment 5

$c = 3;
}

/**
* Passed examples.
* @return void
*/
function wfPassedExamples() {
$a = 1;

$b = 2;
}
37 changes: 37 additions & 0 deletions MO4/Tests/WhiteSpace/MultipleEmptyLinesUnitTest.pass.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/**
* license header etc.
*/

/**
* Failed examples.
* @return void
*/
function wfFailedExamples() {
$a = 1;

$b = 2;

// Comment

// Comment 2

// Comment 3

/* Comment 4 */

# Comment 5

$c = 3;
}

/**
* Passed examples.
* @return void
*/
function wfPassedExamples() {
$a = 1;

$b = 2;
}
45 changes: 45 additions & 0 deletions MO4/Tests/WhiteSpace/MultipleEmptyLinesUnitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/**
* This file is part of the mo4-coding-standard (phpcs standard)
*
* @author Xaver Loppenstedt <[email protected]>
*
* @license http://spdx.org/licenses/MIT MIT License
*
* @link https://github.com/mayflower/mo4-coding-standard
*/

declare(strict_types=1);

namespace MO4\Tests\WhiteSpace;

use MO4\Tests\AbstractMo4SniffUnitTest;

/**
* Unit test class for the MultipleEmptyLines sniff.
*
* A sniff unit test checks a .inc file for expected violations of a single
* coding standard. Expected errors and warnings are stored in this class.
*
* @author Xaver Loppenstedt <[email protected]>
*
* @copyright 2013 Xaver Loppenstedt, some rights reserved.
*
* @license http://spdx.org/licenses/MIT MIT License
*
* @link https://github.com/mayflower/mo4-coding-standard
*/
class MultipleEmptyLinesUnitTest extends AbstractMo4SniffUnitTest
{
protected $expectedErrorList = [
'MultipleEmptyLinesUnitTest.pass.inc' => [],
'MultipleEmptyLinesUnitTest.fail.inc' => [
2 => 1,
14 => 1,
21 => 1,
24 => 1,
29 => 1,
],
];
}
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ To change the sorting order for your project, add this snippet to your custom `r
### MO4.Strings.VariableInDoubleQuotedString
* Interpolated variables in double quoted strings must be surrounded by `{ }`, e.g. `{$VAR}` instead of `$VAR`.

## MO4.WhiteSpace.ConstantSpacing

### MO4.WhiteSpace.ConstantSpacing
* const must be followed by a single space.

### MO4.WhiteSpace.MultipleEmptyLines
* No more than one empty consecutive line is allowed. Taken from [mediawiki/mediawiki-codesniffer](https://github.com/wikimedia/mediawiki-tools-codesniffer).

### Further rules (imported from other standards)
* See `MO4/ruleset.xml`, which has each imported rule commented.

Expand Down

0 comments on commit 5f63628

Please sign in to comment.