annotate vendor/psy/psysh/src/Formatter/DocblockFormatter.php @ 19:fa3358dc1485 tip

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