33f450e1af50d5af6286301c94e2d2ef82372eeb
[yaffs-website] / vendor / psy / psysh / src / Formatter / DocblockFormatter.php
1 <?php
2
3 /*
4  * This file is part of Psy Shell.
5  *
6  * (c) 2012-2018 Justin Hileman
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Psy\Formatter;
13
14 use Psy\Util\Docblock;
15 use Symfony\Component\Console\Formatter\OutputFormatter;
16
17 /**
18  * A pretty-printer for docblocks.
19  */
20 class DocblockFormatter implements Formatter
21 {
22     private static $vectorParamTemplates = [
23         'type' => 'info',
24         'var'  => 'strong',
25     ];
26
27     /**
28      * Format a docblock.
29      *
30      * @param \Reflector $reflector
31      *
32      * @return string Formatted docblock
33      */
34     public static function format(\Reflector $reflector)
35     {
36         $docblock = new Docblock($reflector);
37         $chunks   = [];
38
39         if (!empty($docblock->desc)) {
40             $chunks[] = '<comment>Description:</comment>';
41             $chunks[] = self::indent(OutputFormatter::escape($docblock->desc), '  ');
42             $chunks[] = '';
43         }
44
45         if (!empty($docblock->tags)) {
46             foreach ($docblock::$vectors as $name => $vector) {
47                 if (isset($docblock->tags[$name])) {
48                     $chunks[] = sprintf('<comment>%s:</comment>', self::inflect($name));
49                     $chunks[] = self::formatVector($vector, $docblock->tags[$name]);
50                     $chunks[] = '';
51                 }
52             }
53
54             $tags = self::formatTags(array_keys($docblock::$vectors), $docblock->tags);
55             if (!empty($tags)) {
56                 $chunks[] = $tags;
57                 $chunks[] = '';
58             }
59         }
60
61         return rtrim(implode("\n", $chunks));
62     }
63
64     /**
65      * Format a docblock vector, for example, `@throws`, `@param`, or `@return`.
66      *
67      * @see DocBlock::$vectors
68      *
69      * @param array $vector
70      * @param array $lines
71      *
72      * @return string
73      */
74     private static function formatVector(array $vector, array $lines)
75     {
76         $template = [' '];
77         foreach ($vector as $type) {
78             $max = 0;
79             foreach ($lines as $line) {
80                 $chunk = $line[$type];
81                 $cur = empty($chunk) ? 0 : strlen($chunk) + 1;
82                 if ($cur > $max) {
83                     $max = $cur;
84                 }
85             }
86
87             $template[] = self::getVectorParamTemplate($type, $max);
88         }
89         $template = implode(' ', $template);
90
91         return implode("\n", array_map(function ($line) use ($template) {
92             $escaped = array_map(['Symfony\Component\Console\Formatter\OutputFormatter', 'escape'], $line);
93
94             return rtrim(vsprintf($template, $escaped));
95         }, $lines));
96     }
97
98     /**
99      * Format docblock tags.
100      *
101      * @param array $skip Tags to exclude
102      * @param array $tags Tags to format
103      *
104      * @return string formatted tags
105      */
106     private static function formatTags(array $skip, array $tags)
107     {
108         $chunks = [];
109
110         foreach ($tags as $name => $values) {
111             if (in_array($name, $skip)) {
112                 continue;
113             }
114
115             foreach ($values as $value) {
116                 $chunks[] = sprintf('<comment>%s%s</comment> %s', self::inflect($name), empty($value) ? '' : ':', OutputFormatter::escape($value));
117             }
118
119             $chunks[] = '';
120         }
121
122         return implode("\n", $chunks);
123     }
124
125     /**
126      * Get a docblock vector template.
127      *
128      * @param string $type Vector type
129      * @param int    $max  Pad width
130      *
131      * @return string
132      */
133     private static function getVectorParamTemplate($type, $max)
134     {
135         if (!isset(self::$vectorParamTemplates[$type])) {
136             return sprintf('%%-%ds', $max);
137         }
138
139         return sprintf('<%s>%%-%ds</%s>', self::$vectorParamTemplates[$type], $max, self::$vectorParamTemplates[$type]);
140     }
141
142     /**
143      * Indent a string.
144      *
145      * @param string $text   String to indent
146      * @param string $indent (default: '  ')
147      *
148      * @return string
149      */
150     private static function indent($text, $indent = '  ')
151     {
152         return $indent . str_replace("\n", "\n" . $indent, $text);
153     }
154
155     /**
156      * Convert underscored or whitespace separated words into sentence case.
157      *
158      * @param string $text
159      *
160      * @return string
161      */
162     private static function inflect($text)
163     {
164         $words = trim(preg_replace('/[\s_-]+/', ' ', preg_replace('/([a-z])([A-Z])/', '$1 $2', $text)));
165
166         return implode(' ', array_map('ucfirst', explode(' ', $words)));
167     }
168 }