You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
5.7 KiB

3 years ago
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Console\Descriptor;
  11. use Symfony\Component\Console\Application;
  12. use Symfony\Component\Console\Command\Command;
  13. use Symfony\Component\Console\Input\InputArgument;
  14. use Symfony\Component\Console\Input\InputDefinition;
  15. use Symfony\Component\Console\Input\InputOption;
  16. /**
  17. * JSON descriptor.
  18. *
  19. * @author Jean-François Simon <contact@jfsimon.fr>
  20. *
  21. * @internal
  22. */
  23. class JsonDescriptor extends Descriptor
  24. {
  25. /**
  26. * {@inheritdoc}
  27. */
  28. protected function describeInputArgument(InputArgument $argument, array $options = [])
  29. {
  30. $this->writeData($this->getInputArgumentData($argument), $options);
  31. }
  32. /**
  33. * {@inheritdoc}
  34. */
  35. protected function describeInputOption(InputOption $option, array $options = [])
  36. {
  37. $this->writeData($this->getInputOptionData($option), $options);
  38. if ($option->isNegatable()) {
  39. $this->writeData($this->getInputOptionData($option, true), $options);
  40. }
  41. }
  42. /**
  43. * {@inheritdoc}
  44. */
  45. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  46. {
  47. $this->writeData($this->getInputDefinitionData($definition), $options);
  48. }
  49. /**
  50. * {@inheritdoc}
  51. */
  52. protected function describeCommand(Command $command, array $options = [])
  53. {
  54. $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options);
  55. }
  56. /**
  57. * {@inheritdoc}
  58. */
  59. protected function describeApplication(Application $application, array $options = [])
  60. {
  61. $describedNamespace = $options['namespace'] ?? null;
  62. $description = new ApplicationDescription($application, $describedNamespace, true);
  63. $commands = [];
  64. foreach ($description->getCommands() as $command) {
  65. $commands[] = $this->getCommandData($command, $options['short'] ?? false);
  66. }
  67. $data = [];
  68. if ('UNKNOWN' !== $application->getName()) {
  69. $data['application']['name'] = $application->getName();
  70. if ('UNKNOWN' !== $application->getVersion()) {
  71. $data['application']['version'] = $application->getVersion();
  72. }
  73. }
  74. $data['commands'] = $commands;
  75. if ($describedNamespace) {
  76. $data['namespace'] = $describedNamespace;
  77. } else {
  78. $data['namespaces'] = array_values($description->getNamespaces());
  79. }
  80. $this->writeData($data, $options);
  81. }
  82. /**
  83. * Writes data as json.
  84. */
  85. private function writeData(array $data, array $options)
  86. {
  87. $flags = $options['json_encoding'] ?? 0;
  88. $this->write(json_encode($data, $flags));
  89. }
  90. private function getInputArgumentData(InputArgument $argument): array
  91. {
  92. return [
  93. 'name' => $argument->getName(),
  94. 'is_required' => $argument->isRequired(),
  95. 'is_array' => $argument->isArray(),
  96. 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
  97. 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
  98. ];
  99. }
  100. private function getInputOptionData(InputOption $option, bool $negated = false): array
  101. {
  102. return $negated ? [
  103. 'name' => '--no-'.$option->getName(),
  104. 'shortcut' => '',
  105. 'accept_value' => false,
  106. 'is_value_required' => false,
  107. 'is_multiple' => false,
  108. 'description' => 'Negate the "--'.$option->getName().'" option',
  109. 'default' => false,
  110. ] : [
  111. 'name' => '--'.$option->getName(),
  112. 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
  113. 'accept_value' => $option->acceptValue(),
  114. 'is_value_required' => $option->isValueRequired(),
  115. 'is_multiple' => $option->isArray(),
  116. 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()),
  117. 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault(),
  118. ];
  119. }
  120. private function getInputDefinitionData(InputDefinition $definition): array
  121. {
  122. $inputArguments = [];
  123. foreach ($definition->getArguments() as $name => $argument) {
  124. $inputArguments[$name] = $this->getInputArgumentData($argument);
  125. }
  126. $inputOptions = [];
  127. foreach ($definition->getOptions() as $name => $option) {
  128. $inputOptions[$name] = $this->getInputOptionData($option);
  129. if ($option->isNegatable()) {
  130. $inputOptions['no-'.$name] = $this->getInputOptionData($option, true);
  131. }
  132. }
  133. return ['arguments' => $inputArguments, 'options' => $inputOptions];
  134. }
  135. private function getCommandData(Command $command, bool $short = false): array
  136. {
  137. $data = [
  138. 'name' => $command->getName(),
  139. 'description' => $command->getDescription(),
  140. ];
  141. if ($short) {
  142. $data += [
  143. 'usage' => $command->getAliases(),
  144. ];
  145. } else {
  146. $command->mergeApplicationDefinition(false);
  147. $data += [
  148. 'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),
  149. 'help' => $command->getProcessedHelp(),
  150. 'definition' => $this->getInputDefinitionData($command->getDefinition()),
  151. ];
  152. }
  153. $data['hidden'] = $command->isHidden();
  154. return $data;
  155. }
  156. }