PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file ShorthandSizeSniff.php

Documentation is available at ShorthandSizeSniff.php

  1. <?php
  2. /**
  3.  * Ensure sizes are defined using shorthand notation where possible.
  4.  *
  5.  * @author    Greg Sherwood <gsherwood@squiz.net>
  6.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  7.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  8.  */
  9.  
  10. namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14.  
  15. class ShorthandSizeSniff implements Sniff
  16. {
  17.  
  18.     /**
  19.      * A list of tokenizers this sniff supports.
  20.      *
  21.      * @var array 
  22.      */
  23.     public $supportedTokenizers = array('CSS');
  24.  
  25.     /**
  26.      * A list of styles that we shouldn't check.
  27.      *
  28.      * These have values that looks like sizes, but are not.
  29.      *
  30.      * @var array 
  31.      */
  32.     protected $excludeStyles = array(
  33.                                 'background-position'      => 'background-position',
  34.                                 'box-shadow'               => 'box-shadow',
  35.                                 'transform-origin'         => 'transform-origin',
  36.                                 '-webkit-transform-origin' => '-webkit-transform-origin',
  37.                                 '-ms-transform-origin'     => '-ms-transform-origin',
  38.                                );
  39.  
  40.  
  41.     /**
  42.      * Returns the token types that this sniff is interested in.
  43.      *
  44.      * @return int[] 
  45.      */
  46.     public function register()
  47.     {
  48.         return array(T_STYLE);
  49.  
  50.     }//end register()
  51.  
  52.  
  53.     /**
  54.      * Processes the tokens that this sniff is interested in.
  55.      *
  56.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where the token was found.
  57.      * @param int                         $stackPtr  The position in the stack where
  58.      *                                                the token was found.
  59.      *
  60.      * @return void 
  61.      */
  62.     public function process(File $phpcsFile, $stackPtr)
  63.     {
  64.         $tokens = $phpcsFile->getTokens();
  65.  
  66.         // Some styles look like shorthand but are not actually a set of 4 sizes.
  67.         $style = strtolower($tokens[$stackPtr]['content']);
  68.         if (isset($this->excludeStyles[$style]) === true) {
  69.             return;
  70.         }
  71.  
  72.         // Get the whole style content.
  73.         $end         = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1));
  74.         $origContent = $phpcsFile->getTokensAsString(($stackPtr + 1), ($end - $stackPtr - 1));
  75.         $origContent = trim($origContent, ': ');
  76.  
  77.         // Account for a !important annotation.
  78.         $content = $origContent;
  79.         if (substr($content, -10) === '!important') {
  80.             $content = substr($content, 0, -10);
  81.             $content = trim($content);
  82.         }
  83.  
  84.         // Check if this style value is a set of numbers with optional prefixes.
  85.         $content = preg_replace('/\s+/', ' ', $content);
  86.         $values  = array();
  87.         $num     = preg_match_all(
  88.             '/([0-9]+)([a-zA-Z]{2}\s+|%\s+|\s+)/',
  89.             $content.' ',
  90.             $values,
  91.             PREG_SET_ORDER
  92.         );
  93.  
  94.         // Only interested in styles that have multiple sizes defined.
  95.         if ($num < 2) {
  96.             return;
  97.         }
  98.  
  99.         // Rebuild the content we matched to ensure we got everything.
  100.         $matched = '';
  101.         foreach ($values as $value) {
  102.             $matched .= $value[0];
  103.         }
  104.  
  105.         if ($content !== trim($matched)) {
  106.             return;
  107.         }
  108.  
  109.         if ($num === 3) {
  110.             $expected = trim($content.' '.$values[1][1].$values[1][2]);
  111.             $error    = 'Shorthand syntax not allowed here; use %s instead';
  112.             $data     = array($expected);
  113.             $fix      = $phpcsFile->addFixableError($error, $stackPtr, 'NotAllowed', $data);
  114.  
  115.             if ($fix === true) {
  116.                 $phpcsFile->fixer->beginChangeset();
  117.                 if (substr($origContent, -10) === '!important') {
  118.                     $expected .= ' !important';
  119.                 }
  120.  
  121.                 $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 2), null, true);
  122.                 $phpcsFile->fixer->replaceToken($next, $expected);
  123.                 for ($next++; $next < $end; $next++) {
  124.                     $phpcsFile->fixer->replaceToken($next, '');
  125.                 }
  126.  
  127.                 $phpcsFile->fixer->endChangeset();
  128.             }
  129.  
  130.             return;
  131.         }//end if
  132.  
  133.         if ($num === 2) {
  134.             if ($values[0][0] !== $values[1][0]) {
  135.                 // Both values are different, so it is already shorthand.
  136.                 return;
  137.             }
  138.         } else if ($values[0][0] !== $values[2][0] || $values[1][0] !== $values[3][0]) {
  139.             // Can't shorthand this.
  140.             return;
  141.         }
  142.  
  143.         if ($values[0][0] === $values[1][0]) {
  144.             // All values are the same.
  145.             $expected = $values[0][0];
  146.         } else {
  147.             $expected = $values[0][0].' '.$values[1][0];
  148.         }
  149.  
  150.         $expected = preg_replace('/\s+/', ' ', trim($expected));
  151.  
  152.         $error = 'Size definitions must use shorthand if available; expected "%s" but found "%s"';
  153.         $data  = array(
  154.                   $expected,
  155.                   $content,
  156.                  );
  157.  
  158.         $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NotUsed', $data);
  159.         if ($fix === true) {
  160.             $phpcsFile->fixer->beginChangeset();
  161.             if (substr($origContent, -10) === '!important') {
  162.                 $expected .= ' !important';
  163.             }
  164.  
  165.             $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 2), null, true);
  166.             $phpcsFile->fixer->replaceToken($next, $expected);
  167.             for ($next++; $next < $end; $next++) {
  168.                 $phpcsFile->fixer->replaceToken($next, '');
  169.             }
  170.  
  171.             $phpcsFile->fixer->endChangeset();
  172.         }
  173.  
  174.     }//end process()
  175.  
  176.  
  177. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:46 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.