You are here

class EndFileNewlineSniff in Coder 8.3.x

Same name and namespace in other branches
  1. 8.3 coder_sniffer/Drupal/Sniffs/Files/EndFileNewlineSniff.php \Drupal\Sniffs\Files\EndFileNewlineSniff
  2. 8.2 coder_sniffer/Drupal/Sniffs/Files/EndFileNewlineSniff.php \Drupal\Sniffs\Files\EndFileNewlineSniff

Ensures the file ends with a newline character.

Largely copied from PSR2, but we need to run it on *.txt files and templates as well.

@category PHP @package PHP_CodeSniffer @link http://pear.php.net/package/PHP_CodeSniffer

Hierarchy

Expanded class hierarchy of EndFileNewlineSniff

File

coder_sniffer/Drupal/Sniffs/Files/EndFileNewlineSniff.php, line 25

Namespace

Drupal\Sniffs\Files
View source
class EndFileNewlineSniff implements Sniff {

  /**
   * A list of tokenizers this sniff supports.
   *
   * @var array<string>
   */
  public $supportedTokenizers = [
    'PHP',
    'JS',
    'CSS',
  ];

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

  //end register()

  /**
   * Processes this sniff, 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 int|void
   */
  public function process(File $phpcsFile, $stackPtr) {

    // Skip to the end of the file.
    $tokens = $phpcsFile
      ->getTokens();
    if ($phpcsFile->tokenizerType === 'PHP') {
      $lastToken = $phpcsFile->numTokens - 1;
    }
    else {

      // JS and CSS have an artificial token at the end which we have to
      // ignore.
      $lastToken = $phpcsFile->numTokens - 2;
    }

    // Hard-coding the expected \n in this sniff as it is PSR-2 specific and
    // PSR-2 enforces the use of unix style newlines.
    if (substr($tokens[$lastToken]['content'], -1) !== "\n") {
      $error = 'Expected 1 newline at end of file; 0 found';
      $fix = $phpcsFile
        ->addFixableError($error, $lastToken, 'NoneFound');
      if ($fix === true) {
        $phpcsFile->fixer
          ->addNewline($lastToken);
      }
      $phpcsFile
        ->recordMetric($stackPtr, 'Number of newlines at EOF', '0');
      return $phpcsFile->numTokens + 1;
    }

    // Go looking for the last non-empty line.
    $lastLine = $tokens[$lastToken]['line'];
    if ($tokens[$lastToken]['code'] === T_WHITESPACE) {
      $lastCode = $phpcsFile
        ->findPrevious(T_WHITESPACE, $lastToken - 1, null, true);
    }
    else {
      if ($tokens[$lastToken]['code'] === T_INLINE_HTML) {
        $lastCode = $lastToken;
        while ($lastCode > 0 && trim($tokens[$lastCode]['content']) === '') {
          $lastCode--;
        }
      }
      else {
        $lastCode = $lastToken;
      }
    }
    $lastCodeLine = $tokens[$lastCode]['line'];
    $blankLines = (string) ($lastLine - $lastCodeLine + 1);
    $phpcsFile
      ->recordMetric($stackPtr, 'Number of newlines at EOF', $blankLines);
    if ($blankLines > 1) {
      $error = 'Expected 1 newline at end of file; %s found';
      $data = [
        $blankLines,
      ];
      $fix = $phpcsFile
        ->addFixableError($error, $lastCode, 'TooMany', $data);
      if ($fix === true) {
        $phpcsFile->fixer
          ->beginChangeset();
        $phpcsFile->fixer
          ->replaceToken($lastCode, rtrim($tokens[$lastCode]['content']));
        for ($i = $lastCode + 1; $i < $lastToken; $i++) {
          $phpcsFile->fixer
            ->replaceToken($i, '');
        }
        $phpcsFile->fixer
          ->replaceToken($lastToken, $phpcsFile->eolChar);
        $phpcsFile->fixer
          ->endChangeset();
      }
    }

    // Skip the rest of the file.
    return $phpcsFile->numTokens + 1;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EndFileNewlineSniff::$supportedTokenizers public property A list of tokenizers this sniff supports.
EndFileNewlineSniff::process public function Processes this sniff, when one of its tokens is encountered.
EndFileNewlineSniff::register public function Returns an array of tokens this test wants to listen for.