/** * {@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))); } } }
/** * Constructor. Register built in Transformers. */ private function __construct() { $this->registerBuiltInTransformers(); usort($this->items, function (TransformerInterface $a, TransformerInterface $b) { return Utils::cmpInt($b->getPriority(), $a->getPriority()); }); }
/** * 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)); } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $ending = $this->whitespacesConfig->getLineEnding(); $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]); } $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, $ending . $ending . $indent))); } else { $newline = $ending; $tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG) ? --$insertIndex : ++$insertIndex; 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 (null === $afterSemicolon || !$tokens[$afterSemicolon]->isGivenKind(T_USE)) { $newline .= $ending; } 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 { $tokens->insertAt($insertIndex, new Token(array(T_WHITESPACE, $newline . $indent))); } } } }
/** * {@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)); } }
/** * Create a new docblock instance. * * @param string $content */ public function __construct($content) { foreach (Utils::splitLines($content) as $line) { $this->lines[] = new Line($line); } }
/** * 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); }
/** * @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); }
/** * 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; }
/** * @return string */ protected function getFixerName() { $reflection = new \ReflectionClass($this); $name = preg_replace('/FixerTest$/', '', $reflection->getShortName()); return Utils::camelCaseToUnderscore($name); }
/** * 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); }
/** * @param string[]|null $options JSON encode option * * @return string */ public function toJson(array $options = null) { static $defaultOptions = null; if (null === $options) { if (null === $defaultOptions) { $defaultOptions = Utils::calculateBitmask(array('JSON_PRETTY_PRINT', 'JSON_NUMERIC_CHECK')); } $options = $defaultOptions; } else { $options = Utils::calculateBitmask($options); } return json_encode($this->toArray(), $options); }
/** * {@inheritdoc} */ public function getName() { $nameParts = explode('\\', get_called_class()); $name = substr(end($nameParts), 0, -strlen('Fixer')); return Utils::camelCaseToUnderscore($name); }
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); }