T_STRING, self::SECOND_LEVEL_COMMENT => T_DEC, ]; /** * A list of tokenizers this sniff supports. * * @var array */ public $supportedTokenizers = [TokenizerSymbolsInterface::TOKENIZER_CSS]; /** * @inheritdoc */ public function register() { return [T_STRING]; } /** * @inheritdoc */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ((T_STRING !== $tokens[$stackPtr]['code']) || (self::COMMENT_STRING !== $tokens[$stackPtr]['content']) || (1 === $tokens[$stackPtr]['line']) ) { return; } $textInSameLine = $phpcsFile->findPrevious([T_STRING, T_STYLE], $stackPtr - 1); // is inline comment if ((false !== $textInSameLine) && ($tokens[$textInSameLine]['line'] === $tokens[$stackPtr]['line']) ) { $this->validateInlineComment($phpcsFile, $stackPtr, $tokens); return; } // validation of levels comments if (!in_array($tokens[$stackPtr + 1]['content'], [ TokenizerSymbolsInterface::DOUBLE_WHITESPACE, TokenizerSymbolsInterface::NEW_LINE, ]) ) { $phpcsFile->addError('Level\'s comment does not have 2 spaces after "//"', $stackPtr, 'SpacesMissed'); } if (!$this->isNthLevelComment($phpcsFile, $stackPtr, $tokens)) { return; } if (!$this->checkNthLevelComment($phpcsFile, $stackPtr, $tokens)) { $phpcsFile->addError( 'First and second level comments must be surrounded by empty lines', $stackPtr, 'SpaceMissed' ); } } /** * Validate that inline comment responds to given requirements * * @param File $phpcsFile * @param int $stackPtr * @param array $tokens * @return bool */ private function validateInlineComment(File $phpcsFile, $stackPtr, array $tokens) { if ($tokens[$stackPtr + 1]['content'] !== TokenizerSymbolsInterface::WHITESPACE) { $phpcsFile->addError('Inline comment should have 1 space after "//"', $stackPtr, 'SpaceMissedAfter'); } if ($tokens[$stackPtr - 1]['content'] !== TokenizerSymbolsInterface::WHITESPACE) { $phpcsFile->addError('Inline comment should have 1 space before "//"', $stackPtr, 'SpaceMissedBefore'); } } /** * Check is it n-th level comment was found * * @param File $phpcsFile * @param int $stackPtr * @param array $tokens * @return bool */ private function isNthLevelComment(File $phpcsFile, $stackPtr, array $tokens) { $nthLevelCommentFound = false; $levelComment = 0; foreach ($this->levelComments as $code => $comment) { $levelComment = $phpcsFile->findNext($comment, $stackPtr, null, false, $code); if (false !== $levelComment) { $nthLevelCommentFound = true; break; } } if (false === $nthLevelCommentFound) { return false; } $currentLine = $tokens[$stackPtr]['line']; $levelCommentLine = $tokens[$levelComment]['line']; if ($currentLine !== $levelCommentLine) { return false; } return true; } /** * Check is it n-th level comment is correct * * @param File $phpcsFile * @param int $stackPtr * @param array $tokens * @return bool */ private function checkNthLevelComment(File $phpcsFile, $stackPtr, array $tokens) { $correct = false; $nextLine = $phpcsFile->findNext( T_WHITESPACE, $stackPtr, null, false, TokenizerSymbolsInterface::NEW_LINE ); if (false === $nextLine) { return $correct; } if (($tokens[$nextLine]['content'] !== TokenizerSymbolsInterface::NEW_LINE) || ($tokens[$nextLine + 1]['content'] !== TokenizerSymbolsInterface::NEW_LINE) ) { return $correct; } $commentLinePtr = $stackPtr; while ($tokens[$commentLinePtr - 2]['line'] > 1) { $commentLinePtr = $phpcsFile->findPrevious(T_STRING, $commentLinePtr - 1, null, false, '//'); if (false === $commentLinePtr) { continue; } if (($tokens[$commentLinePtr - 1]['content'] === TokenizerSymbolsInterface::NEW_LINE) && ($tokens[$commentLinePtr - 2]['content'] === TokenizerSymbolsInterface::NEW_LINE) ) { $correct = true; break; } } return $correct; } }