summaryrefslogtreecommitdiff
path: root/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php')
-rw-r--r--vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php272
1 files changed, 272 insertions, 0 deletions
diff --git a/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php
new file mode 100644
index 0000000..f12fecb
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php
@@ -0,0 +1,272 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Console\Descriptor;
13
14use Symfony\Component\Console\Application;
15use Symfony\Component\Console\Command\Command;
16use Symfony\Component\Console\Helper\Helper;
17use Symfony\Component\Console\Input\InputArgument;
18use Symfony\Component\Console\Input\InputDefinition;
19use Symfony\Component\Console\Input\InputOption;
20use Symfony\Component\Console\Output\OutputInterface;
21use Symfony\Component\String\UnicodeString;
22
23class ReStructuredTextDescriptor extends Descriptor
24{
25 // <h1>
26 private string $partChar = '=';
27 // <h2>
28 private string $chapterChar = '-';
29 // <h3>
30 private string $sectionChar = '~';
31 // <h4>
32 private string $subsectionChar = '.';
33 // <h5>
34 private string $subsubsectionChar = '^';
35 // <h6>
36 private string $paragraphsChar = '"';
37
38 private array $visibleNamespaces = [];
39
40 public function describe(OutputInterface $output, object $object, array $options = []): void
41 {
42 $decorated = $output->isDecorated();
43 $output->setDecorated(false);
44
45 parent::describe($output, $object, $options);
46
47 $output->setDecorated($decorated);
48 }
49
50 /**
51 * Override parent method to set $decorated = true.
52 */
53 protected function write(string $content, bool $decorated = true): void
54 {
55 parent::write($content, $decorated);
56 }
57
58 protected function describeInputArgument(InputArgument $argument, array $options = []): void
59 {
60 $this->write(
61 $argument->getName() ?: '<none>'."\n".str_repeat($this->paragraphsChar, Helper::width($argument->getName()))."\n\n"
62 .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '')
63 .'- **Is required**: '.($argument->isRequired() ? 'yes' : 'no')."\n"
64 .'- **Is array**: '.($argument->isArray() ? 'yes' : 'no')."\n"
65 .'- **Default**: ``'.str_replace("\n", '', var_export($argument->getDefault(), true)).'``'
66 );
67 }
68
69 protected function describeInputOption(InputOption $option, array $options = []): void
70 {
71 $name = '\-\-'.$option->getName();
72 if ($option->isNegatable()) {
73 $name .= '|\-\-no-'.$option->getName();
74 }
75 if ($option->getShortcut()) {
76 $name .= '|-'.str_replace('|', '|-', $option->getShortcut());
77 }
78
79 $optionDescription = $option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n\n", $option->getDescription())."\n\n" : '';
80 $optionDescription = (new UnicodeString($optionDescription))->ascii();
81 $this->write(
82 $name."\n".str_repeat($this->paragraphsChar, Helper::width($name))."\n\n"
83 .$optionDescription
84 .'- **Accept value**: '.($option->acceptValue() ? 'yes' : 'no')."\n"
85 .'- **Is value required**: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
86 .'- **Is multiple**: '.($option->isArray() ? 'yes' : 'no')."\n"
87 .'- **Is negatable**: '.($option->isNegatable() ? 'yes' : 'no')."\n"
88 .'- **Default**: ``'.str_replace("\n", '', var_export($option->getDefault(), true)).'``'."\n"
89 );
90 }
91
92 protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
93 {
94 if ($showArguments = ((bool) $definition->getArguments())) {
95 $this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9))."\n\n";
96 foreach ($definition->getArguments() as $argument) {
97 $this->write("\n\n");
98 $this->describeInputArgument($argument);
99 }
100 }
101
102 if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) {
103 if ($showArguments) {
104 $this->write("\n\n");
105 }
106
107 $this->write("Options\n".str_repeat($this->subsubsectionChar, 7)."\n\n");
108 foreach ($nonDefaultOptions as $option) {
109 $this->describeInputOption($option);
110 $this->write("\n");
111 }
112 }
113 }
114
115 protected function describeCommand(Command $command, array $options = []): void
116 {
117 if ($options['short'] ?? false) {
118 $this->write(
119 '``'.$command->getName()."``\n"
120 .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n"
121 .($command->getDescription() ? $command->getDescription()."\n\n" : '')
122 ."Usage\n".str_repeat($this->paragraphsChar, 5)."\n\n"
123 .array_reduce($command->getAliases(), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n")
124 );
125
126 return;
127 }
128
129 $command->mergeApplicationDefinition(false);
130
131 foreach ($command->getAliases() as $alias) {
132 $this->write('.. _'.$alias.":\n\n");
133 }
134 $this->write(
135 $command->getName()."\n"
136 .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n"
137 .($command->getDescription() ? $command->getDescription()."\n\n" : '')
138 ."Usage\n".str_repeat($this->subsubsectionChar, 5)."\n\n"
139 .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n")
140 );
141
142 if ($help = $command->getProcessedHelp()) {
143 $this->write("\n");
144 $this->write($help);
145 }
146
147 $definition = $command->getDefinition();
148 if ($definition->getOptions() || $definition->getArguments()) {
149 $this->write("\n\n");
150 $this->describeInputDefinition($definition);
151 }
152 }
153
154 protected function describeApplication(Application $application, array $options = []): void
155 {
156 $description = new ApplicationDescription($application, $options['namespace'] ?? null);
157 $title = $this->getApplicationTitle($application);
158
159 $this->write($title."\n".str_repeat($this->partChar, Helper::width($title)));
160 $this->createTableOfContents($description, $application);
161 $this->describeCommands($application, $options);
162 }
163
164 private function getApplicationTitle(Application $application): string
165 {
166 if ('UNKNOWN' === $application->getName()) {
167 return 'Console Tool';
168 }
169 if ('UNKNOWN' !== $application->getVersion()) {
170 return sprintf('%s %s', $application->getName(), $application->getVersion());
171 }
172
173 return $application->getName();
174 }
175
176 private function describeCommands($application, array $options): void
177 {
178 $title = 'Commands';
179 $this->write("\n\n$title\n".str_repeat($this->chapterChar, Helper::width($title))."\n\n");
180 foreach ($this->visibleNamespaces as $namespace) {
181 if ('_global' === $namespace) {
182 $commands = $application->all('');
183 $this->write('Global'."\n".str_repeat($this->sectionChar, Helper::width('Global'))."\n\n");
184 } else {
185 $commands = $application->all($namespace);
186 $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n");
187 }
188
189 foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) {
190 $this->describeCommand($command, $options);
191 $this->write("\n\n");
192 }
193 }
194 }
195
196 private function createTableOfContents(ApplicationDescription $description, Application $application): void
197 {
198 $this->setVisibleNamespaces($description);
199 $chapterTitle = 'Table of Contents';
200 $this->write("\n\n$chapterTitle\n".str_repeat($this->chapterChar, Helper::width($chapterTitle))."\n\n");
201 foreach ($this->visibleNamespaces as $namespace) {
202 if ('_global' === $namespace) {
203 $commands = $application->all('');
204 } else {
205 $commands = $application->all($namespace);
206 $this->write("\n\n");
207 $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n");
208 }
209 $commands = $this->removeAliasesAndHiddenCommands($commands);
210
211 $this->write("\n\n");
212 $this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands))));
213 }
214 }
215
216 private function getNonDefaultOptions(InputDefinition $definition): array
217 {
218 $globalOptions = [
219 'help',
220 'quiet',
221 'verbose',
222 'version',
223 'ansi',
224 'no-interaction',
225 ];
226 $nonDefaultOptions = [];
227 foreach ($definition->getOptions() as $option) {
228 // Skip global options.
229 if (!\in_array($option->getName(), $globalOptions, true)) {
230 $nonDefaultOptions[] = $option;
231 }
232 }
233
234 return $nonDefaultOptions;
235 }
236
237 private function setVisibleNamespaces(ApplicationDescription $description): void
238 {
239 $commands = $description->getCommands();
240 foreach ($description->getNamespaces() as $namespace) {
241 try {
242 $namespaceCommands = $namespace['commands'];
243 foreach ($namespaceCommands as $key => $commandName) {
244 if (!\array_key_exists($commandName, $commands)) {
245 // If the array key does not exist, then this is an alias.
246 unset($namespaceCommands[$key]);
247 } elseif ($commands[$commandName]->isHidden()) {
248 unset($namespaceCommands[$key]);
249 }
250 }
251 if (!$namespaceCommands) {
252 // If the namespace contained only aliases or hidden commands, skip the namespace.
253 continue;
254 }
255 } catch (\Exception) {
256 }
257 $this->visibleNamespaces[] = $namespace['id'];
258 }
259 }
260
261 private function removeAliasesAndHiddenCommands(array $commands): array
262 {
263 foreach ($commands as $key => $command) {
264 if ($command->isHidden() || \in_array($key, $command->getAliases(), true)) {
265 unset($commands[$key]);
266 }
267 }
268 unset($commands['completion']);
269
270 return $commands;
271 }
272}