/**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, Tokens $tokens)
 {
     $tokensAnalyzer = new TokensAnalyzer($tokens);
     foreach ($tokensAnalyzer->getImportUseIndexes() as $index) {
         $indent = '';
         // if previous line ends with comment and current line starts with whitespace, use current indent
         if ($tokens[$index - 1]->isWhitespace(" \t") && $tokens[$index - 2]->isGivenKind(T_COMMENT)) {
             $indent = $tokens[$index - 1]->getContent();
         } elseif ($tokens[$index - 1]->isWhitespace()) {
             $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]);
         }
         $newline = "\n";
         // Handle insert index for inline T_COMMENT with whitespace after semicolon
         $semicolonIndex = $tokens->getNextTokenOfKind($index, array(';', '{'));
         $insertIndex = $semicolonIndex + 1;
         if ($tokens[$insertIndex]->isWhitespace(" \t") && $tokens[$insertIndex + 1]->isComment()) {
             ++$insertIndex;
         }
         // Increment insert index for inline T_COMMENT or T_DOC_COMMENT
         if ($tokens[$insertIndex]->isComment()) {
             ++$insertIndex;
         }
         $afterSemicolon = $tokens->getNextMeaningfulToken($semicolonIndex);
         if (!$tokens[$afterSemicolon]->isGivenKind(T_USE)) {
             $newline .= "\n";
         }
         if ($tokens[$insertIndex]->isWhitespace()) {
             $nextToken = $tokens[$insertIndex];
             $nextToken->setContent($newline . $indent . ltrim($nextToken->getContent()));
         } elseif ($newline && $indent) {
             $tokens->insertAt($insertIndex, new Token(array(T_WHITESPACE, $newline . $indent)));
         }
     }
 }
 public function fix(\SplFileInfo $file, $content)
 {
     $tokens = Tokens::fromCode($content);
     foreach ($tokens->getImportUseIndexes() as $index) {
         $indent = '';
         if ($tokens[$index - 1]->isWhitespace(array('whitespaces' => " \t")) && $tokens[$index - 2]->isGivenKind(T_COMMENT)) {
             $indent = $tokens[$index - 1]->getContent();
         } elseif ($tokens[$index - 1]->isWhitespace()) {
             $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]);
         }
         $newline = "\n";
         $semicolonIndex = $tokens->getNextTokenOfKind($index, array(';', '{'));
         $insertIndex = $semicolonIndex + 1;
         if ($tokens[$insertIndex]->isWhitespace(array('whitespaces' => " \t")) && $tokens[$insertIndex + 1]->isComment()) {
             ++$insertIndex;
         }
         if ($tokens[$insertIndex]->isGivenKind(T_COMMENT)) {
             $newline = '';
         }
         if ($tokens[$insertIndex]->isComment()) {
             ++$insertIndex;
         }
         $afterSemicolon = $tokens->getNextMeaningfulToken($semicolonIndex);
         if (!$tokens[$afterSemicolon]->isGivenKind(T_USE)) {
             $newline .= "\n";
         }
         if ($tokens[$insertIndex]->isWhitespace()) {
             $nextToken = $tokens[$insertIndex];
             $nextToken->setContent($newline . $indent . ltrim($nextToken->getContent()));
         } else {
             $tokens->insertAt($insertIndex, new Token(array(T_WHITESPACE, $newline . $indent)));
         }
     }
     return $tokens->generateCode();
 }
 private function fixWhitespace(Token $token)
 {
     $content = $token->getContent();
     if (substr_count($content, "\n") > 1) {
         $lines = Utils::splitLines($content);
         $token->setContent("\n" . end($lines));
     }
 }
 /**
  * Cleanup a whitespace token.
  *
  * @param Token $token
  */
 private function fixWhitespace(Token $token)
 {
     $content = $token->getContent();
     // if there is more than one new line in the whitespace, then we need to fix it
     if (substr_count($content, "\n") > 1) {
         // the final bit of the whitespace must be the next statement's indentation
         $lines = Utils::splitLines($content);
         $token->setContent("\n" . end($lines));
     }
 }
예제 #5
0
 /**
  * Fix a given docblock.
  *
  * @param string $content
  *
  * @return string
  */
 private function fixDocBlock($content)
 {
     $lines = Utils::splitLines($content);
     $l = count($lines);
     for ($i = 0; $i < $l; ++$i) {
         $items = array();
         $matches = $this->getMatches($lines[$i]);
         if (null === $matches) {
             continue;
         }
         $current = $i;
         $items[] = $matches;
         while ($matches = $this->getMatches($lines[++$i], true)) {
             $items[] = $matches;
         }
         // compute the max length of the tag, hint and variables
         $tagMax = 0;
         $hintMax = 0;
         $varMax = 0;
         foreach ($items as $item) {
             if (null === $item['tag']) {
                 continue;
             }
             $tagMax = max($tagMax, strlen($item['tag']));
             $hintMax = max($hintMax, strlen($item['hint']));
             $varMax = max($varMax, strlen($item['var']));
         }
         $currTag = null;
         // update
         foreach ($items as $j => $item) {
             if (null === $item['tag']) {
                 if ($item['desc'][0] === '@') {
                     $lines[$current + $j] = $item['indent'] . ' * ' . $item['desc'] . "\n";
                     continue;
                 }
                 $line = $item['indent'] . ' *  ' . str_repeat(' ', $tagMax + $hintMax + $varMax + ('param' === $currTag ? 3 : 2)) . $item['desc'] . "\n";
                 $lines[$current + $j] = $line;
                 continue;
             }
             $currTag = $item['tag'];
             $line = $item['indent'] . ' * @' . $item['tag'] . str_repeat(' ', $tagMax - strlen($item['tag']) + 1) . $item['hint'];
             if (!empty($item['var'])) {
                 $line .= str_repeat(' ', $hintMax - strlen($item['hint']) + 1) . $item['var'] . (!empty($item['desc']) ? str_repeat(' ', $varMax - strlen($item['var']) + 1) . $item['desc'] . "\n" : "\n");
             } elseif (!empty($item['desc'])) {
                 $line .= str_repeat(' ', $hintMax - strlen($item['hint']) + 1) . $item['desc'] . "\n";
             } else {
                 $line .= "\n";
             }
             $lines[$current + $j] = $line;
         }
     }
     return implode($lines);
 }
 /**
  * Fix a given docblock.
  *
  * @param string $content
  *
  * @return string
  */
 protected function fixDocBlock($content)
 {
     $lines = Utils::splitLines($content);
     $l = count($lines);
     for ($i = 0; $i < $l; ++$i) {
         $items = [];
         $matches = $this->getMatches($lines[$i]);
         if (!$matches) {
             continue;
         }
         $current = $i;
         $items[] = $matches;
         while ($matches = $this->getMatches($lines[++$i], true)) {
             $items[] = $matches;
         }
         foreach ($items as $j => $item) {
             $pieces = explode('|', $item['hint']);
             $hints = [];
             foreach ($pieces as $piece) {
                 $hints[] = trim($piece);
             }
             $desc = trim($item['desc']);
             while (!empty($desc) && mb_substr($desc, 0, 1) === '|') {
                 $desc = trim(mb_substr($desc, 1));
                 $pos = mb_strpos($desc, ' ');
                 if ($pos > 0) {
                     $hints[] = trim(mb_substr($desc, 0, $pos));
                     $desc = trim(mb_substr($desc, $pos));
                 } else {
                     $hints[] = $desc;
                     $desc = '';
                 }
             }
             $item['hint'] = implode('|', $hints);
             $item['desc'] = $desc;
             $line = $item['indent'] . ' * @' . $item['tag'] . ' ' . $item['hint'];
             if (!empty($item['var'])) {
                 $line .= ' ' . $item['var'] . (!empty($item['desc']) ? ' ' . $item['desc'] . "\n" : "\n");
             } elseif (!empty($item['desc'])) {
                 $line .= ' ' . $item['desc'] . "\n";
             } else {
                 $line .= "\n";
             }
             $lines[$current + $j] = $line;
         }
     }
     return implode($lines);
 }
예제 #7
0
 private function getBestDelimiter($pattern)
 {
     $delimiters = array();
     foreach (self::$delimiters as $k => $d) {
         if (false === strpos($pattern, $d)) {
             return $d;
         }
         $delimiters[$d] = array(substr_count($pattern, $d), $k);
     }
     uasort($delimiters, function ($a, $b) {
         if ($a[0] === $b[0]) {
             return Utils::cmpInt($a, $b);
         }
         return $a[0] < $b[0] ? -1 : 1;
     });
     return key($delimiters);
 }
예제 #8
0
 public function fix(\SplFileInfo $file, $content)
 {
     $tokens = Tokens::fromCode($content);
     foreach ($tokens->findGivenKind(T_DOC_COMMENT) as $index => $token) {
         $nextIndex = $tokens->getNextMeaningfulToken($index);
         if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) {
             continue;
         }
         $prevToken = $tokens[$index - 1];
         if ($prevToken->isGivenKind(T_OPEN_TAG) || $prevToken->isWhitespace(array('whitespaces' => " \t")) && !$tokens[$index - 2]->isGivenKind(T_OPEN_TAG) || $prevToken->equalsAny(array(';', '{'))) {
             continue;
         }
         $indent = '';
         if ($tokens[$nextIndex - 1]->isWhitespace()) {
             $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$nextIndex - 1]);
         }
         $prevToken->setContent($this->fixWhitespaceBefore($prevToken->getContent(), $indent));
         $token->setContent($this->fixDocBlock($token->getContent(), $indent));
     }
     return $tokens->generateCode();
 }
 /**
  * @param \SplFileInfo $file
  * @param string $content
  *
  * @return string
  */
 public function fix(\SplFileInfo $file, $content)
 {
     $tokens = Tokens::fromCode($content);
     for ($index = $tokens->count() - 1; $index >= 0; --$index) {
         /* @var Token $token */
         $token = $tokens[$index];
         // We skip T_FOR, T_WHILE for now as they can have valid inline assignment
         if (!$token->isGivenKind([T_FOREACH, T_IF, T_SWITCH])) {
             continue;
         }
         $startIndex = $tokens->getNextMeaningfulToken($index);
         $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
         $indexEqualSign = null;
         $hasInlineAssignment = $this->hasInlineAssignment($index, $endIndex, $tokens, $indexEqualSign);
         if (!$hasInlineAssignment) {
             continue;
         }
         // Extract to own $var into line above
         $string = '';
         $var = '';
         for ($i = $startIndex + 1; $i < $endIndex; ++$i) {
             $string .= $tokens[$i]->getContent();
             if ($i < $indexEqualSign) {
                 $var .= $tokens[$i]->getContent();
             }
             $tokens[$i]->clear();
         }
         $string .= ';';
         $tokens[$i - 1]->setContent(trim($var));
         $content = $tokens[$index]->getContent();
         $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]);
         $content = $indent . $content;
         $content = $string . PHP_EOL . $content;
         $tokens[$index]->setContent($content);
     }
     return $tokens->generateCode();
 }
예제 #10
0
 /**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, Tokens $tokens)
 {
     foreach ($tokens as $index => $token) {
         if (!$token->isGivenKind(T_DOC_COMMENT)) {
             continue;
         }
         $nextIndex = $tokens->getNextMeaningfulToken($index);
         // skip if there is no next token or if next token is block end `}`
         if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) {
             continue;
         }
         $prevToken = $tokens[$index - 1];
         // ignore inline docblocks
         if ($prevToken->isGivenKind(T_OPEN_TAG) || $prevToken->isWhitespace(" \t") && !$tokens[$index - 2]->isGivenKind(T_OPEN_TAG) || $prevToken->equalsAny(array(';', '{'))) {
             continue;
         }
         $indent = '';
         if ($tokens[$nextIndex - 1]->isWhitespace()) {
             $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$nextIndex - 1]);
         }
         $prevToken->setContent($this->fixWhitespaceBefore($prevToken->getContent(), $indent));
         $token->setContent($this->fixDocBlock($token->getContent(), $indent));
     }
 }
예제 #11
0
 private function sortFixers()
 {
     usort($this->fixers, function (FixerInterface $a, FixerInterface $b) {
         return Utils::cmpInt($b->getPriority(), $a->getPriority());
     });
 }
예제 #12
0
 public function toJson()
 {
     static $options = null;
     if (null === $options) {
         $options = Utils::calculateBitmask(array('JSON_PRETTY_PRINT', 'JSON_NUMERIC_CHECK'));
     }
     $output = new \SplFixedArray(count($this));
     foreach ($this as $index => $token) {
         $output[$index] = $token->toArray();
     }
     $this->rewind();
     return json_encode($output, $options);
 }
예제 #13
0
 /**
  * Sort fixers by their priorities.
  *
  * @return $this
  */
 private function sortFixers()
 {
     // Schwartzian transform is used to improve the efficiency and avoid
     // `usort(): Array was modified by the user comparison function` warning for mocked objects.
     $data = array_map(function (FixerInterface $fixer) {
         return array($fixer, $fixer->getPriority());
     }, $this->fixers);
     usort($data, function (array $a, array $b) {
         return Utils::cmpInt($b[1], $a[1]);
     });
     $this->fixers = array_map(function (array $item) {
         return $item[0];
     }, $data);
     return $this;
 }
예제 #14
0
 /**
  * {@inheritdoc}
  */
 public function getName()
 {
     $nameParts = explode('\\', get_called_class());
     $name = end($nameParts);
     return Utils::camelCaseToUnderscore($name);
 }
 /**
  * @return string
  */
 protected function getFixerName()
 {
     $reflection = new \ReflectionClass($this);
     $name = preg_replace('/FixerTest$/', '', $reflection->getShortName());
     return Utils::camelCaseToUnderscore($name);
 }
 /**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, $content)
 {
     $tokens = Tokens::fromCode($content);
     foreach ($tokens->getImportUseIndexes() as $index) {
         $indent = '';
         // if previous line ends with comment and current line starts with whitespace, use current indent
         if ($tokens[$index - 1]->isWhitespace(array('whitespaces' => " \t")) && $tokens[$index - 2]->isGivenKind(T_COMMENT)) {
             $indent = $tokens[$index - 1]->getContent();
         } elseif ($tokens[$index - 1]->isWhitespace()) {
             $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]);
         }
         $semicolonIndex = $tokens->getNextTokenOfKind($index, array(';', array(T_CLOSE_TAG)));
         // Handle insert index for inline T_COMMENT with whitespace after semicolon
         $insertIndex = $semicolonIndex;
         if ($tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG)) {
             if ($tokens[$insertIndex - 1]->isWhitespace()) {
                 --$insertIndex;
             }
             $tokens->insertAt($insertIndex, new Token(';'));
         }
         if ($semicolonIndex === count($tokens) - 1) {
             $tokens->insertAt($insertIndex + 1, new Token(array(T_WHITESPACE, "\n\n" . $indent)));
         } else {
             $newline = "\n";
             $tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG) ? --$insertIndex : ++$insertIndex;
             if ($tokens[$insertIndex]->isWhitespace(array('whitespaces' => " \t")) && $tokens[$insertIndex + 1]->isComment()) {
                 ++$insertIndex;
             }
             // Do not add newline after inline T_COMMENT as it is part of T_COMMENT already
             // TODO: remove on 2.x line
             if ($tokens[$insertIndex]->isGivenKind(T_COMMENT) && false !== strpos($tokens[$insertIndex]->getContent(), "\n")) {
                 $newline = '';
             }
             // Increment insert index for inline T_COMMENT or T_DOC_COMMENT
             if ($tokens[$insertIndex]->isComment()) {
                 ++$insertIndex;
             }
             $afterSemicolon = $tokens->getNextMeaningfulToken($semicolonIndex);
             if (null === $afterSemicolon || !$tokens[$afterSemicolon]->isGivenKind(T_USE)) {
                 $newline .= "\n";
             }
             if ($tokens[$insertIndex]->isWhitespace()) {
                 $nextToken = $tokens[$insertIndex];
                 $nextMeaningfulAfterUseIndex = $tokens->getNextMeaningfulToken($insertIndex);
                 if (null !== $nextMeaningfulAfterUseIndex && $tokens[$nextMeaningfulAfterUseIndex]->isGivenKind(T_USE)) {
                     if (substr_count($nextToken->getContent(), "\n") < 2) {
                         $nextToken->setContent($newline . $indent . ltrim($nextToken->getContent()));
                     }
                 } else {
                     $nextToken->setContent($newline . $indent . ltrim($nextToken->getContent()));
                 }
             } else {
                 // TODO: remove check on 2.x line
                 if ('' !== $newline . $indent) {
                     $tokens->insertAt($insertIndex, new Token(array(T_WHITESPACE, $newline . $indent)));
                 }
             }
         }
     }
     return $tokens->generateCode();
 }
예제 #17
0
 protected function getFixersHelp()
 {
     $help = '';
     $maxName = 0;
     $fixers = $this->fixer->getFixers();
     // sort fixers by level and name
     usort($fixers, function (FixerInterface $a, FixerInterface $b) {
         $cmp = Utils::cmpInt($a->getLevel(), $b->getLevel());
         if (0 !== $cmp) {
             return $cmp;
         }
         return strcmp($a->getName(), $b->getName());
     });
     foreach ($fixers as $fixer) {
         if (strlen($fixer->getName()) > $maxName) {
             $maxName = strlen($fixer->getName());
         }
     }
     $count = count($fixers) - 1;
     foreach ($fixers as $i => $fixer) {
         $chunks = explode("\n", wordwrap(sprintf("[%s]\n%s", $this->fixer->getLevelAsString($fixer), $fixer->getDescription()), 72 - $maxName, "\n"));
         $help .= sprintf(" * <comment>%s</comment>%s %s\n", $fixer->getName(), str_repeat(' ', $maxName - strlen($fixer->getName())), array_shift($chunks));
         while ($c = array_shift($chunks)) {
             $help .= str_repeat(' ', $maxName + 4) . $c . "\n";
         }
         if ($count !== $i) {
             $help .= "\n";
         }
     }
     return $help;
 }
예제 #18
0
 /**
  * Get the delimiter that would require the least escaping in a regular expression.
  *
  * @param string $pattern the regular expression
  *
  * @return string the preg delimiter
  */
 private function getBestDelimiter($pattern)
 {
     // try do find something that's not used
     $delimiters = array();
     foreach (self::$delimiters as $k => $d) {
         if (false === strpos($pattern, $d)) {
             return $d;
         }
         $delimiters[$d] = array(substr_count($pattern, $d), $k);
     }
     // return the least used delimiter, using the position in the list as a tie breaker
     uasort($delimiters, function ($a, $b) {
         if ($a[0] === $b[0]) {
             return Utils::cmpInt($a, $b);
         }
         return $a[0] < $b[0] ? -1 : 1;
     });
     return key($delimiters);
 }
예제 #19
0
 /**
  * @expectedException \InvalidArgumentException
  * @expectedExceptionMessage The given token must be whitespace, got "T_STRING".
  */
 public function testCalculateTrailingWhitespaceIndentFail()
 {
     $token = new Token(array(T_STRING, 'foo'));
     Utils::calculateTrailingWhitespaceIndent($token);
 }
 /**
  * @dataProvider provideCmpIntCases
  */
 public function testcmpInt($expected, $left, $right)
 {
     $this->assertSame($expected, Utils::cmpInt($left, $right));
 }
예제 #21
0
 public function toJson()
 {
     static $options = null;
     if (null === $options) {
         $options = Utils::calculateBitmask(array('JSON_PRETTY_PRINT', 'JSON_NUMERIC_CHECK'));
     }
     return json_encode($this->toArray(), $options);
 }
예제 #22
0
 /**
  * Sort registered Transformers.
  */
 private function sortTransformers()
 {
     usort($this->items, function (TransformerInterface $a, TransformerInterface $b) {
         return Utils::cmpInt($b->getPriority(), $a->getPriority());
     });
 }
예제 #23
0
 /**
  * Create a new docblock instance.
  *
  * @param string $content
  */
 public function __construct($content)
 {
     foreach (Utils::splitLines($content) as $line) {
         $this->lines[] = new Line($line);
     }
 }
예제 #24
0
 /**
  * {@inheritdoc}
  */
 public function getName()
 {
     $nameParts = explode('\\', get_called_class());
     $name = substr(end($nameParts), 0, -strlen('Checker'));
     return Utils::camelCaseToUnderscore($name);
 }
예제 #25
0
 /**
  * @param FixerInterface[] $fixers
  *
  * @return FixerInterface[]
  */
 private function sortFixers(array $fixers)
 {
     usort($fixers, function (FixerInterface $a, FixerInterface $b) {
         return Utils::cmpInt($b->getPriority(), $a->getPriority());
     });
     return $fixers;
 }