|
@@ -12,11 +12,14 @@
|
|
|
|
|
|
namespace PhpCsFixer\Console\Command;
|
|
namespace PhpCsFixer\Console\Command;
|
|
|
|
|
|
-use PhpCsFixer\ConfigurationException\UnallowedFixerConfigurationException;
|
|
|
|
use PhpCsFixer\Differ\DiffConsoleFormatter;
|
|
use PhpCsFixer\Differ\DiffConsoleFormatter;
|
|
use PhpCsFixer\Differ\SebastianBergmannDiffer;
|
|
use PhpCsFixer\Differ\SebastianBergmannDiffer;
|
|
|
|
+use PhpCsFixer\Fixer\ConfigurableFixerInterface;
|
|
|
|
+use PhpCsFixer\Fixer\DescribedFixerInterface;
|
|
|
|
+use PhpCsFixer\Fixer\FixerInterface;
|
|
|
|
+use PhpCsFixer\FixerDefinition;
|
|
|
|
+use PhpCsFixer\FixerDefinitionInterface;
|
|
use PhpCsFixer\FixerFactory;
|
|
use PhpCsFixer\FixerFactory;
|
|
-use PhpCsFixer\FixerInterface;
|
|
|
|
use PhpCsFixer\RuleSet;
|
|
use PhpCsFixer\RuleSet;
|
|
use PhpCsFixer\ShortFixerDefinition;
|
|
use PhpCsFixer\ShortFixerDefinition;
|
|
use PhpCsFixer\StdinFileInfo;
|
|
use PhpCsFixer\StdinFileInfo;
|
|
@@ -28,11 +31,22 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|
|
|
|
|
/**
|
|
/**
|
|
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
|
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
|
|
|
+ * @author SpacePossum
|
|
*
|
|
*
|
|
* @internal
|
|
* @internal
|
|
*/
|
|
*/
|
|
final class DescribeCommand extends Command
|
|
final class DescribeCommand extends Command
|
|
{
|
|
{
|
|
|
|
+ /**
|
|
|
|
+ * @var string[]
|
|
|
|
+ */
|
|
|
|
+ private $setNames;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @var array<string, FixerInterface>
|
|
|
|
+ */
|
|
|
|
+ private $fixers;
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* {@inheritdoc}
|
|
* {@inheritdoc}
|
|
*/
|
|
*/
|
|
@@ -55,31 +69,46 @@ final class DescribeCommand extends Command
|
|
protected function execute(InputInterface $input, OutputInterface $output)
|
|
protected function execute(InputInterface $input, OutputInterface $output)
|
|
{
|
|
{
|
|
$name = $input->getArgument('name');
|
|
$name = $input->getArgument('name');
|
|
|
|
+ try {
|
|
|
|
+ if ('@' === $name[0]) {
|
|
|
|
+ $this->describeSet($output, $name);
|
|
|
|
|
|
- if ('@' === substr($name, 0, 1)) {
|
|
|
|
- $this->describeSet($input, $output, $name);
|
|
|
|
- } else {
|
|
|
|
- $this->describeRule($input, $output, $name);
|
|
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $this->describeRule($output, $name);
|
|
|
|
+ } catch (DescribeNameNotFoundException $e) {
|
|
|
|
+ $alternative = $this->getAlternative($e->getType(), $name);
|
|
|
|
+ $this->describeList($output, $e->getType());
|
|
|
|
+
|
|
|
|
+ throw new \InvalidArgumentException(sprintf(
|
|
|
|
+ '%s %s not found.%s',
|
|
|
|
+ ucfirst($e->getType()), $name, null === $alternative ? '' : ' Did you mean "'.$alternative.'"?'
|
|
|
|
+ ));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private function describeRule(InputInterface $input, OutputInterface $output, $name)
|
|
|
|
|
|
+ /**
|
|
|
|
+ * @param OutputInterface $output
|
|
|
|
+ * @param string $name
|
|
|
|
+ */
|
|
|
|
+ private function describeRule(OutputInterface $output, $name)
|
|
{
|
|
{
|
|
- $fixerFactory = new FixerFactory();
|
|
|
|
- $fixers = array();
|
|
|
|
-
|
|
|
|
- foreach ($fixerFactory->registerBuiltInFixers()->getFixers() as $fixer) {
|
|
|
|
- $fixers[$fixer->getName()] = $fixer;
|
|
|
|
- }
|
|
|
|
|
|
+ $fixers = $this->getFixers();
|
|
|
|
|
|
if (!isset($fixers[$name])) {
|
|
if (!isset($fixers[$name])) {
|
|
- throw new \InvalidArgumentException(sprintf('Rule "%s" does not exist.', $name));
|
|
|
|
|
|
+ throw new DescribeNameNotFoundException($name, 'rule');
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /** @var FixerInterface $fixer */
|
|
$fixer = $fixers[$name];
|
|
$fixer = $fixers[$name];
|
|
- $definition = $fixer->getDefinition();
|
|
|
|
|
|
+ if ($fixer instanceof DescribedFixerInterface) {
|
|
|
|
+ $definition = $fixer->getDefinition();
|
|
|
|
+ } else {
|
|
|
|
+ $definition = new FixerDefinition('[n/a]', '[n/a]', array(), null);
|
|
|
|
+ }
|
|
|
|
|
|
- $output->writeln(sprintf('<info>Description of %s rule.</info>', $name));
|
|
|
|
|
|
+ $output->writeln(sprintf('<info>Description of</info> %s <info>rule</info>.', $name));
|
|
$output->writeln($definition->getSummary());
|
|
$output->writeln($definition->getSummary());
|
|
if ($definition->getDescription()) {
|
|
if ($definition->getDescription()) {
|
|
$output->writeln($definition->getDescription());
|
|
$output->writeln($definition->getDescription());
|
|
@@ -96,7 +125,7 @@ final class DescribeCommand extends Command
|
|
$output->writeln('');
|
|
$output->writeln('');
|
|
}
|
|
}
|
|
|
|
|
|
- if ($this->isFixerConfigurable($fixer)) {
|
|
|
|
|
|
+ if ($fixer instanceof ConfigurableFixerInterface) {
|
|
$output->writeln('<comment>Fixer is configurable.</comment>');
|
|
$output->writeln('<comment>Fixer is configurable.</comment>');
|
|
|
|
|
|
if ($definition->getConfigurationDescription()) {
|
|
if ($definition->getConfigurationDescription()) {
|
|
@@ -123,7 +152,10 @@ final class DescribeCommand extends Command
|
|
foreach ($definition->getCodeSamples() as $index => $codeSample) {
|
|
foreach ($definition->getCodeSamples() as $index => $codeSample) {
|
|
$old = $codeSample[0];
|
|
$old = $codeSample[0];
|
|
$tokens = Tokens::fromCode($old);
|
|
$tokens = Tokens::fromCode($old);
|
|
- $fixer->configure($codeSample[1]);
|
|
|
|
|
|
+ if ($fixer instanceof ConfigurableFixerInterface) {
|
|
|
|
+ $fixer->configure($codeSample[1]);
|
|
|
|
+ }
|
|
|
|
+
|
|
$fixer->fix(new StdinFileInfo(), $tokens);
|
|
$fixer->fix(new StdinFileInfo(), $tokens);
|
|
$new = $tokens->generateCode();
|
|
$new = $tokens->generateCode();
|
|
$diff = $differ->diff($old, $new);
|
|
$diff = $differ->diff($old, $new);
|
|
@@ -140,36 +172,40 @@ final class DescribeCommand extends Command
|
|
|
|
|
|
if ($definition instanceof ShortFixerDefinition) {
|
|
if ($definition instanceof ShortFixerDefinition) {
|
|
$output->writeln(sprintf('<question>This rule is not yet described, do you want to help us and describe it?</question>'));
|
|
$output->writeln(sprintf('<question>This rule is not yet described, do you want to help us and describe it?</question>'));
|
|
- $output->writeln('Contribute at <comment>https://github.com/FriendsOfPHP/PHP-CS-Fixer</comment>');
|
|
|
|
|
|
+ $output->writeln('Contribute at <comment>https://github.com/FriendsOfPHP/PHP-CS-Fixer</comment> !');
|
|
$output->writeln('');
|
|
$output->writeln('');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private function describeSet(InputInterface $input, OutputInterface $output, $name)
|
|
|
|
|
|
+ /**
|
|
|
|
+ * @param OutputInterface $output
|
|
|
|
+ * @param string $name
|
|
|
|
+ */
|
|
|
|
+ private function describeSet(OutputInterface $output, $name)
|
|
{
|
|
{
|
|
|
|
+ if (!in_array($name, $this->getSetNames(), true)) {
|
|
|
|
+ throw new DescribeNameNotFoundException($name, 'set');
|
|
|
|
+ }
|
|
|
|
+
|
|
$ruleSet = new RuleSet(array($name => true));
|
|
$ruleSet = new RuleSet(array($name => true));
|
|
$rules = $ruleSet->getRules();
|
|
$rules = $ruleSet->getRules();
|
|
ksort($rules);
|
|
ksort($rules);
|
|
|
|
|
|
- $fixerFactory = new FixerFactory();
|
|
|
|
- $fixers = array();
|
|
|
|
|
|
+ $fixers = $this->getFixers();
|
|
|
|
|
|
- foreach ($fixerFactory->registerBuiltInFixers()->getFixers() as $fixer) {
|
|
|
|
- $fixers[$fixer->getName()] = $fixer;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $output->writeln(sprintf('<info>Description of %s set.</info>', $name));
|
|
|
|
|
|
+ $output->writeln(sprintf('<info>Description of</info> %s <info>set.</info>', $name));
|
|
$output->writeln('');
|
|
$output->writeln('');
|
|
|
|
|
|
$help = '';
|
|
$help = '';
|
|
|
|
|
|
- $count = count($rules) - 1;
|
|
|
|
foreach ($rules as $rule => $config) {
|
|
foreach ($rules as $rule => $config) {
|
|
|
|
+ /** @var FixerDefinitionInterface $definition */
|
|
|
|
+ $definition = $fixers[$rule]->getDefinition();
|
|
$help .= sprintf(
|
|
$help .= sprintf(
|
|
" * <info>%s</info>%s\n | %s\n%s\n",
|
|
" * <info>%s</info>%s\n | %s\n%s\n",
|
|
$rule,
|
|
$rule,
|
|
- $fixers[$rule]->isRisky() ? ' <error>[risky]</error>' : '',
|
|
|
|
- $fixers[$rule]->getDescription(),
|
|
|
|
|
|
+ $fixers[$rule]->isRisky() ? ' <error>risky</error>' : '',
|
|
|
|
+ $definition->getSummary(),
|
|
true !== $config ? sprintf(" <comment>| Configuration: %s</comment>\n", $this->arrayToText($config)) : ''
|
|
true !== $config ? sprintf(" <comment>| Configuration: %s</comment>\n", $this->arrayToText($config)) : ''
|
|
);
|
|
);
|
|
}
|
|
}
|
|
@@ -178,23 +214,10 @@ final class DescribeCommand extends Command
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * @param FixerInterface $fixer
|
|
|
|
|
|
+ * @param array $data
|
|
*
|
|
*
|
|
- * @return bool
|
|
|
|
|
|
+ * @return string
|
|
*/
|
|
*/
|
|
- private function isFixerConfigurable(FixerInterface $fixer)
|
|
|
|
- {
|
|
|
|
- try {
|
|
|
|
- $fixer->configure(array());
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
- } catch (UnallowedFixerConfigurationException $e) {
|
|
|
|
- return false;
|
|
|
|
- } catch (\Exception $e) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
private function arrayToText(array $data)
|
|
private function arrayToText(array $data)
|
|
{
|
|
{
|
|
// Output modifications:
|
|
// Output modifications:
|
|
@@ -215,4 +238,91 @@ final class DescribeCommand extends Command
|
|
var_export($data, true)
|
|
var_export($data, true)
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @return array<string, FixerInterface>
|
|
|
|
+ */
|
|
|
|
+ private function getFixers()
|
|
|
|
+ {
|
|
|
|
+ if (null !== $this->fixers) {
|
|
|
|
+ return $this->fixers;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $fixerFactory = new FixerFactory();
|
|
|
|
+ $fixers = array();
|
|
|
|
+
|
|
|
|
+ foreach ($fixerFactory->registerBuiltInFixers()->getFixers() as $fixer) {
|
|
|
|
+ $fixers[$fixer->getName()] = $fixer;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $this->fixers = $fixers;
|
|
|
|
+ ksort($this->fixers);
|
|
|
|
+
|
|
|
|
+ return $this->fixers;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @return string[]
|
|
|
|
+ */
|
|
|
|
+ private function getSetNames()
|
|
|
|
+ {
|
|
|
|
+ if (null !== $this->setNames) {
|
|
|
|
+ return $this->setNames;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $set = new RuleSet();
|
|
|
|
+ $this->setNames = $set->getSetDefinitionNames();
|
|
|
|
+ sort($this->setNames);
|
|
|
|
+
|
|
|
|
+ return $this->setNames;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @param string $type 'rule'|'set'
|
|
|
|
+ * @param string $name
|
|
|
|
+ *
|
|
|
|
+ * @return null|string
|
|
|
|
+ */
|
|
|
|
+ private function getAlternative($type, $name)
|
|
|
|
+ {
|
|
|
|
+ $other = null;
|
|
|
|
+ $alternatives = 'set' === $type ? $this->getSetNames() : array_keys($this->getFixers());
|
|
|
|
+
|
|
|
|
+ foreach ($alternatives as $alternative) {
|
|
|
|
+ $distance = levenshtein($name, $alternative);
|
|
|
|
+ if (3 > $distance) {
|
|
|
|
+ $other = $alternative;
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return $other;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @param OutputInterface $output
|
|
|
|
+ * @param string $type 'rule'|'set'
|
|
|
|
+ */
|
|
|
|
+ private function describeList(OutputInterface $output, $type)
|
|
|
|
+ {
|
|
|
|
+ if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE) {
|
|
|
|
+ $describe = array(
|
|
|
|
+ 'set' => $this->getSetNames(),
|
|
|
|
+ 'rules' => $this->getFixers(),
|
|
|
|
+ );
|
|
|
|
+ } elseif ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
|
|
|
|
+ $describe = 'set' === $type ? array('set' => $this->getSetNames()) : array('rules' => $this->getFixers());
|
|
|
|
+ } else {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** @var string[] $items */
|
|
|
|
+ foreach ($describe as $list => $items) {
|
|
|
|
+ $output->writeln(sprintf('<comment>Defined %s:</comment>', $list));
|
|
|
|
+ foreach ($items as $name => $item) {
|
|
|
|
+ $output->writeln(sprintf('* <info>%s</info>', is_string($name) ? $name : $item));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|