/** * {@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)); } }
/** * 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); }
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); }
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(); }
/** * {@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)); } }
private function sortFixers() { usort($this->fixers, function (FixerInterface $a, FixerInterface $b) { return Utils::cmpInt($b->getPriority(), $a->getPriority()); }); }
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); }
/** * 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; }
/** * {@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(); }
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; }
/** * 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); }
/** * @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)); }
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); }
/** * Sort registered Transformers. */ private function sortTransformers() { usort($this->items, function (TransformerInterface $a, TransformerInterface $b) { return Utils::cmpInt($b->getPriority(), $a->getPriority()); }); }
/** * Create a new docblock instance. * * @param string $content */ public function __construct($content) { foreach (Utils::splitLines($content) as $line) { $this->lines[] = new Line($line); } }
/** * {@inheritdoc} */ public function getName() { $nameParts = explode('\\', get_called_class()); $name = substr(end($nameParts), 0, -strlen('Checker')); return Utils::camelCaseToUnderscore($name); }
/** * @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; }