SemicolonSpacingSniff.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Sniffs\Less;
  7. use PHP_CodeSniffer\Sniffs\Sniff;
  8. use PHP_CodeSniffer\Files\File;
  9. /**
  10. * Class SemicolonSpacingSniff
  11. *
  12. * Property should have a semicolon at the end of line
  13. *
  14. * @link https://devdocs.magento.com/guides/v2.0/coding-standards/code-standard-less.html#end-of-the-property-line
  15. */
  16. class SemicolonSpacingSniff implements Sniff
  17. {
  18. /**
  19. * A list of tokenizers this sniff supports.
  20. *
  21. * @var array
  22. */
  23. public $supportedTokenizers = [TokenizerSymbolsInterface::TOKENIZER_CSS];
  24. /**
  25. * Skip symbols that can be detected by sniffer incorrectly
  26. *
  27. * @var array
  28. */
  29. private $styleSymbolsToSkip = [
  30. TokenizerSymbolsInterface::BITWISE_AND,
  31. TokenizerSymbolsInterface::COLON,
  32. TokenizerSymbolsInterface::OPEN_PARENTHESIS,
  33. TokenizerSymbolsInterface::CLOSE_PARENTHESIS,
  34. ];
  35. /** Skip codes that can be detected by sniffer incorrectly
  36. *
  37. * @var array
  38. */
  39. private $styleCodesToSkip = [T_ASPERAND, T_COLON, T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS];
  40. /**
  41. * @inheritdoc
  42. */
  43. public function register()
  44. {
  45. return [T_STYLE];
  46. }
  47. /**
  48. * @inheritdoc
  49. */
  50. public function process(File $phpcsFile, $stackPtr)
  51. {
  52. $tokens = $phpcsFile->getTokens();
  53. if (in_array($tokens[$stackPtr]['content'], $this->styleSymbolsToSkip)) {
  54. return;
  55. }
  56. $semicolonPtr = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1));
  57. if ($tokens[$semicolonPtr]['line'] !== $tokens[$stackPtr]['line']) {
  58. $semicolonPtr = $phpcsFile->findNext(T_STYLE, ($stackPtr + 1), null, false, ";");
  59. }
  60. $this->validateSemicolon($phpcsFile, $stackPtr, $tokens, $semicolonPtr);
  61. $this->validateSpaces($phpcsFile, $stackPtr, $tokens, $semicolonPtr);
  62. }
  63. /**
  64. * Semicolon validation.
  65. *
  66. * @param File $phpcsFile
  67. * @param int $stackPtr
  68. * @param array $tokens
  69. * @param int $semicolonPtr
  70. * @return void
  71. */
  72. private function validateSemicolon(File $phpcsFile, $stackPtr, array $tokens, $semicolonPtr)
  73. {
  74. if ((false === $semicolonPtr || $tokens[$semicolonPtr]['line'] !== $tokens[$stackPtr]['line'])
  75. && (isset($tokens[$stackPtr - 1]) && !in_array($tokens[$stackPtr - 1]['code'], $this->styleCodesToSkip))
  76. && (T_COLON !== $tokens[$stackPtr + 1]['code'])
  77. ) {
  78. $error = 'Style definitions must end with a semicolon';
  79. $phpcsFile->addError($error, $stackPtr, 'NotAtEnd');
  80. }
  81. }
  82. /**
  83. * Spaces validation.
  84. *
  85. * @param File $phpcsFile
  86. * @param int $stackPtr
  87. * @param array $tokens
  88. * @param int $semicolonPtr
  89. * @return void
  90. */
  91. private function validateSpaces(File $phpcsFile, $stackPtr, array $tokens, $semicolonPtr)
  92. {
  93. if (!isset($tokens[($semicolonPtr - 1)])) {
  94. return;
  95. }
  96. if ($tokens[($semicolonPtr - 1)]['code'] === T_WHITESPACE) {
  97. $length = strlen($tokens[($semicolonPtr - 1)]['content']);
  98. $error = 'Expected 0 spaces before semicolon in style definition; %s found';
  99. $data = [$length];
  100. $phpcsFile->addError($error, $stackPtr, 'SpaceFound', $data);
  101. }
  102. }
  103. }