正在显示
22 个修改的文件
包含
853 行增加
和
0 行删除
.gitignore
0 → 100644
composer.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "lackoxygen/showdoc-generation", | ||
| 3 | + "type": "library", | ||
| 4 | + "autoload": { | ||
| 5 | + "psr-4": { | ||
| 6 | + "Lackoxygen\\ShowDocGeneration\\": "src/" | ||
| 7 | + } | ||
| 8 | + }, | ||
| 9 | + "authors": [ | ||
| 10 | + { | ||
| 11 | + "name": "lackoxygen", | ||
| 12 | + "email": "jingze666@gmail.com" | ||
| 13 | + } | ||
| 14 | + ], | ||
| 15 | + "extra": { | ||
| 16 | + "laravel": { | ||
| 17 | + "providers": [ | ||
| 18 | + "Lackoxygen\\ShowDocGeneration\\ShowDocGenerationServiceProvider" | ||
| 19 | + ] | ||
| 20 | + } | ||
| 21 | + }, | ||
| 22 | + "require": { | ||
| 23 | + "doctrine/annotations": "1.14.3" | ||
| 24 | + } | ||
| 25 | +} |
publish/doc.php
0 → 100644
src/Annotations/Annotation.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +abstract class Annotation | ||
| 6 | +{ | ||
| 7 | + public function __construct(array $values) | ||
| 8 | + { | ||
| 9 | + foreach ($this->getSelfProperties() as $property) { | ||
| 10 | + if (isset($values[$property->getName()])) { | ||
| 11 | + $this->{$property->getName()} = $values[$property->getName()]; | ||
| 12 | + } | ||
| 13 | + } | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * @return mixed|\ReflectionProperty[] | ||
| 18 | + */ | ||
| 19 | + protected function getSelfProperties() | ||
| 20 | + { | ||
| 21 | + static $properties; | ||
| 22 | + | ||
| 23 | + if (is_null($properties)) { | ||
| 24 | + $ref = new \ReflectionClass($this); | ||
| 25 | + | ||
| 26 | + $properties = $ref->getProperties(); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + return $properties; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * @return array | ||
| 34 | + */ | ||
| 35 | + public function toArray(): array | ||
| 36 | + { | ||
| 37 | + $array = []; | ||
| 38 | + foreach ($this->getSelfProperties() as $property) { | ||
| 39 | + $array[$property->getName()] = $this->{$property->getName()}; | ||
| 40 | + } | ||
| 41 | + return $array; | ||
| 42 | + } | ||
| 43 | +} |
src/Annotations/Catalog.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +use Doctrine\Common\Annotations\Annotation\Required; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Annotation | ||
| 9 | + * @Target({"METHOD"}) | ||
| 10 | + * @Attributes({}) | ||
| 11 | + */ | ||
| 12 | +final class Catalog extends Annotation | ||
| 13 | +{ | ||
| 14 | + /** | ||
| 15 | + * @Required() | ||
| 16 | + * @var string | ||
| 17 | + */ | ||
| 18 | + protected string $value = ''; | ||
| 19 | +} |
src/Annotations/Description.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Annotation | ||
| 7 | + * @Target({"METHOD"}) | ||
| 8 | + * @Attributes({ | ||
| 9 | +@Attribute("value", type = "string"), | ||
| 10 | + * }) | ||
| 11 | + */ | ||
| 12 | +final class Description extends Annotation | ||
| 13 | +{ | ||
| 14 | + /** | ||
| 15 | + * @Required() | ||
| 16 | + * @var string | ||
| 17 | + */ | ||
| 18 | + protected string $value = ''; | ||
| 19 | +} |
src/Annotations/HeaderLine.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +use Doctrine\Common\Annotations\Annotation\Required; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Annotation | ||
| 9 | + * @Target({"METHOD"}) | ||
| 10 | + * @Attributes({ | ||
| 11 | +@Attribute("key", type = "string"), | ||
| 12 | +@Attribute("remark", type = "string"), | ||
| 13 | + * }) | ||
| 14 | + */ | ||
| 15 | +final class HeaderLine extends Annotation | ||
| 16 | +{ | ||
| 17 | + /** | ||
| 18 | + * @Required() | ||
| 19 | + * @var string | ||
| 20 | + */ | ||
| 21 | + protected string $key = ''; | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * @Required() | ||
| 25 | + * @var string | ||
| 26 | + */ | ||
| 27 | + protected string $remark = ''; | ||
| 28 | +} |
src/Annotations/Method.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +use Doctrine\Common\Annotations\Annotation\Enum; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Annotation | ||
| 9 | + * @Target({"METHOD"}) | ||
| 10 | + * @Attributes({ | ||
| 11 | +@Attribute("method", type = "string"), | ||
| 12 | + * }) | ||
| 13 | + */ | ||
| 14 | +final class Method extends Annotation | ||
| 15 | +{ | ||
| 16 | + public const METHOD_GET = 'GET'; | ||
| 17 | + public const METHOD_POST = 'POST'; | ||
| 18 | + public const METHOD_PUT = 'PUT'; | ||
| 19 | + public const METHOD_PATCH = 'PATCH'; | ||
| 20 | + public const METHOD_DELETE = 'DELETE'; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * @Required() | ||
| 24 | + * @Enum({"GET", "POST", "PUT", "PATCH", "DELETE"}) | ||
| 25 | + * @var string | ||
| 26 | + */ | ||
| 27 | + protected string $method = ''; | ||
| 28 | +} |
src/Annotations/ParamLine.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +use Doctrine\Common\Annotations\Annotation\Required; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Annotation | ||
| 9 | + * @Target({"METHOD"}) | ||
| 10 | + * @Attributes({ | ||
| 11 | +@Attribute("key", type = "string"), | ||
| 12 | +@Attribute("must", type = "bool"), | ||
| 13 | +@Attribute("type", type = "string"), | ||
| 14 | +@Attribute("remark", type = "string"), | ||
| 15 | + * }) | ||
| 16 | + */ | ||
| 17 | +final class ParamLine extends Annotation | ||
| 18 | +{ | ||
| 19 | + /** | ||
| 20 | + * @Required() | ||
| 21 | + * @var string | ||
| 22 | + */ | ||
| 23 | + protected string $key = ''; | ||
| 24 | + /** | ||
| 25 | + * @var bool | ||
| 26 | + */ | ||
| 27 | + protected bool $must = false; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * @Required() | ||
| 31 | + * @var string | ||
| 32 | + */ | ||
| 33 | + protected string $type = ''; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * @Required() | ||
| 37 | + * @var string | ||
| 38 | + */ | ||
| 39 | + protected string $remark = ''; | ||
| 40 | +} |
src/Annotations/Remark.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +use Doctrine\Common\Annotations\Annotation\Required; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Annotation | ||
| 9 | + * @Target({"METHOD"}) | ||
| 10 | + * @Attributes({}) | ||
| 11 | + */ | ||
| 12 | +final class Remark extends Annotation | ||
| 13 | +{ | ||
| 14 | + /** | ||
| 15 | + * @Required() | ||
| 16 | + * @var string | ||
| 17 | + */ | ||
| 18 | + protected string $value = ''; | ||
| 19 | +} |
src/Annotations/Resp.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +use Doctrine\Common\Annotations\Annotation\Required; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Annotation | ||
| 9 | + * @Target({"METHOD"}) | ||
| 10 | + * @Attributes({ | ||
| 11 | +@Attribute("value", type = "string"), | ||
| 12 | + * }) | ||
| 13 | + */ | ||
| 14 | +final class Resp extends Annotation | ||
| 15 | +{ | ||
| 16 | + /** | ||
| 17 | + * @Required() | ||
| 18 | + * @var string | ||
| 19 | + */ | ||
| 20 | + protected string $value = '{}'; | ||
| 21 | +} |
src/Annotations/RespLine.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +use Doctrine\Common\Annotations\Annotation\Required; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Annotation | ||
| 9 | + * @Target({"METHOD"}) | ||
| 10 | + * @Attributes({ | ||
| 11 | +@Attribute("key", type = "string"), | ||
| 12 | +@Attribute("type", type = "string"), | ||
| 13 | +@Attribute("remark", type = "string"), | ||
| 14 | + * }) | ||
| 15 | + */ | ||
| 16 | +class RespLine extends Annotation | ||
| 17 | +{ | ||
| 18 | + /** | ||
| 19 | + * @Required() | ||
| 20 | + * @var string | ||
| 21 | + */ | ||
| 22 | + protected string $key = ''; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * @Required() | ||
| 26 | + * @var string | ||
| 27 | + */ | ||
| 28 | + protected string $type = ''; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * @Required() | ||
| 32 | + * @var string | ||
| 33 | + */ | ||
| 34 | + protected string $remark = ''; | ||
| 35 | +} |
src/Annotations/Title.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Annotation | ||
| 7 | + * @Target({"METHOD"}) | ||
| 8 | + * @Attributes({ | ||
| 9 | +@Attribute("value", type = "string"), | ||
| 10 | + * }) | ||
| 11 | + */ | ||
| 12 | +final class Title extends Annotation | ||
| 13 | +{ | ||
| 14 | + /** | ||
| 15 | + * @Required() | ||
| 16 | + * @var string | ||
| 17 | + */ | ||
| 18 | + protected string $value = ''; | ||
| 19 | +} |
src/Annotations/Url.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Annotations; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Annotation | ||
| 7 | + * @Target({"METHOD"}) | ||
| 8 | + * @Attributes({ | ||
| 9 | +@Attribute("path", type = "string"), | ||
| 10 | + * }) | ||
| 11 | + */ | ||
| 12 | +final class Url extends Annotation | ||
| 13 | +{ | ||
| 14 | + /** | ||
| 15 | + * @Required() | ||
| 16 | + * @var string | ||
| 17 | + */ | ||
| 18 | + protected string $path = ''; | ||
| 19 | +} |
src/Commands/GenerationCommand.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Commands; | ||
| 4 | + | ||
| 5 | +use Illuminate\Console\Command; | ||
| 6 | +use Lackoxygen\ShowDocGeneration\Logger; | ||
| 7 | +use Lackoxygen\ShowDocGeneration\Parser\Paster; | ||
| 8 | +use Lackoxygen\ShowDocGeneration\Writer\Writer; | ||
| 9 | + | ||
| 10 | +class GenerationCommand extends Command | ||
| 11 | +{ | ||
| 12 | + /** | ||
| 13 | + * The name and signature of the console command. | ||
| 14 | + * | ||
| 15 | + * @var string | ||
| 16 | + */ | ||
| 17 | + protected $signature = 'doc {--v : print info} | ||
| 18 | + {--prefix=}'; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * The console command description. | ||
| 22 | + * | ||
| 23 | + * @var string | ||
| 24 | + */ | ||
| 25 | + protected $description = 'generate documentation'; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * Create a new command instance. | ||
| 29 | + * | ||
| 30 | + * @return void | ||
| 31 | + */ | ||
| 32 | + public function __construct() | ||
| 33 | + { | ||
| 34 | + parent::__construct(); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * Execute the console command. | ||
| 39 | + * | ||
| 40 | + * @return int | ||
| 41 | + */ | ||
| 42 | + public function handle() | ||
| 43 | + { | ||
| 44 | + | ||
| 45 | + $v = $this->input->getOption('v'); | ||
| 46 | + | ||
| 47 | + Logger::setMode($v ? Logger::DISPLAY : Logger::NONE); | ||
| 48 | + | ||
| 49 | + Logger::setOutput($this->output); | ||
| 50 | + | ||
| 51 | + Logger::writeln("input option v={$v}"); | ||
| 52 | + | ||
| 53 | + $prefix = $this->input->getOption('prefix') ?? 'api'; | ||
| 54 | + | ||
| 55 | + Logger::writeln("input option prefix={$prefix}"); | ||
| 56 | + | ||
| 57 | + Logger::writeln('parse start'); | ||
| 58 | + $cos = Paster::resolve($this->laravel, $prefix); | ||
| 59 | + | ||
| 60 | + Logger::writeln('parse end'); | ||
| 61 | + | ||
| 62 | + Logger::writeln('write start'); | ||
| 63 | + $writer = new Writer(); | ||
| 64 | + | ||
| 65 | + $writer->puts($cos); | ||
| 66 | + | ||
| 67 | + Logger::writeln('write end'); | ||
| 68 | + | ||
| 69 | + return 0; | ||
| 70 | + } | ||
| 71 | +} |
src/Logger.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration; | ||
| 4 | + | ||
| 5 | +use Symfony\Component\Console\Output\ConsoleOutput; | ||
| 6 | +use Symfony\Component\Console\Output\OutputInterface; | ||
| 7 | + | ||
| 8 | +class Logger | ||
| 9 | +{ | ||
| 10 | + public const NONE = 0; | ||
| 11 | + | ||
| 12 | + public const DISPLAY = 1; | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * @var int | ||
| 16 | + */ | ||
| 17 | + private static int $mode; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * @var OutputInterface $outputInterface | ||
| 21 | + */ | ||
| 22 | + private static OutputInterface $outputInterface; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * @return void | ||
| 26 | + */ | ||
| 27 | + public static function setMode(int $mode) | ||
| 28 | + { | ||
| 29 | + self::$mode = $mode; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public static function setOutput(OutputInterface $output) | ||
| 33 | + { | ||
| 34 | + self::$outputInterface = $output; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public static function writeln(string $message) | ||
| 38 | + { | ||
| 39 | + if (self::$mode) { | ||
| 40 | + self::$outputInterface->writeln(sprintf("[%s]: %s", now()->toString(), $message)); | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | +} |
src/Parser/Doc.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Parser; | ||
| 4 | + | ||
| 5 | +class Doc | ||
| 6 | +{ | ||
| 7 | + public array $catalog = []; | ||
| 8 | + public array $title = []; | ||
| 9 | + | ||
| 10 | + public array $method = []; | ||
| 11 | + | ||
| 12 | + public array $url = []; | ||
| 13 | + | ||
| 14 | + public array $headerLine = []; | ||
| 15 | + | ||
| 16 | + public array $paramLine = []; | ||
| 17 | + | ||
| 18 | + public array $resp = []; | ||
| 19 | + | ||
| 20 | + public array $respLine = []; | ||
| 21 | + | ||
| 22 | + public array $remark = []; | ||
| 23 | + | ||
| 24 | + public array $middles = []; | ||
| 25 | +} |
src/Parser/Paster.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Parser; | ||
| 4 | + | ||
| 5 | +use Illuminate\Foundation\Application; | ||
| 6 | +use Illuminate\Routing\Route; | ||
| 7 | +use Illuminate\Routing\RouteCollection; | ||
| 8 | +use Illuminate\Routing\Router; | ||
| 9 | +use Illuminate\Support\Collection; | ||
| 10 | +use Illuminate\Support\Str; | ||
| 11 | +use Lackoxygen\ShowDocGeneration\Annotations\Annotation; | ||
| 12 | +use Lackoxygen\ShowDocGeneration\Annotations\Catalog; | ||
| 13 | +use Lackoxygen\ShowDocGeneration\Annotations\HeaderLine; | ||
| 14 | +use Lackoxygen\ShowDocGeneration\Annotations\Method; | ||
| 15 | +use Lackoxygen\ShowDocGeneration\Annotations\ParamLine; | ||
| 16 | +use Lackoxygen\ShowDocGeneration\Annotations\Remark; | ||
| 17 | +use Lackoxygen\ShowDocGeneration\Annotations\Resp; | ||
| 18 | +use Lackoxygen\ShowDocGeneration\Annotations\RespLine; | ||
| 19 | +use Lackoxygen\ShowDocGeneration\Annotations\Title; | ||
| 20 | +use Lackoxygen\ShowDocGeneration\Annotations\Url; | ||
| 21 | +use Lackoxygen\ShowDocGeneration\Logger; | ||
| 22 | +use Psr\Container\ContainerExceptionInterface; | ||
| 23 | +use Psr\Container\NotFoundExceptionInterface; | ||
| 24 | + | ||
| 25 | +class Paster | ||
| 26 | +{ | ||
| 27 | + /** | ||
| 28 | + * @var array | ||
| 29 | + */ | ||
| 30 | + protected array $annotations = [ | ||
| 31 | + Catalog::class, | ||
| 32 | + Title::class, | ||
| 33 | + Url::class, | ||
| 34 | + Method::class, | ||
| 35 | + HeaderLine::class, | ||
| 36 | + ParamLine::class, | ||
| 37 | + Resp::class, | ||
| 38 | + RespLine::class, | ||
| 39 | + Remark::class | ||
| 40 | + ]; | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * @var Application | ||
| 44 | + */ | ||
| 45 | + protected Application $application; | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * @var string | ||
| 49 | + */ | ||
| 50 | + protected string $prefix; | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * @var Collection|array | ||
| 54 | + */ | ||
| 55 | + protected Collection $docsCollect; | ||
| 56 | + | ||
| 57 | + public function __construct() | ||
| 58 | + { | ||
| 59 | + $this->docsCollect = collect(); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + /** | ||
| 63 | + * @param Application $application | ||
| 64 | + * @param string|null $prefix | ||
| 65 | + * @return array|Collection | ||
| 66 | + */ | ||
| 67 | + public static function resolve(Application $application, string $prefix = null) | ||
| 68 | + { | ||
| 69 | + $static = new static(); | ||
| 70 | + $static->application = $application; | ||
| 71 | + $static->prefix = $prefix; | ||
| 72 | + try { | ||
| 73 | + $routes = $static->getRoutes(); | ||
| 74 | + | ||
| 75 | + $static->eachRoutes($routes, function (self $self, Route $route) { | ||
| 76 | + Logger::writeln('load ' . join('|', $route->methods()) . ' ' . $route->uri()); | ||
| 77 | + try { | ||
| 78 | + $doc = $self->resolveAnnotation($route); | ||
| 79 | + $doc->middles = $route->middleware(); | ||
| 80 | + $self->docsCollect->push($doc); | ||
| 81 | + } catch (\ReflectionException $e) { | ||
| 82 | + Logger::writeln('error ' . $e->getMessage()); | ||
| 83 | + } | ||
| 84 | + }); | ||
| 85 | + } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) { | ||
| 86 | + Logger::writeln('error ' . $e->getMessage()); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + return $static->docsCollect; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + /** | ||
| 93 | + * @param RouteCollection $routes | ||
| 94 | + * @param $callback | ||
| 95 | + * @return void | ||
| 96 | + */ | ||
| 97 | + protected function eachRoutes(RouteCollection $routes, $callback) | ||
| 98 | + { | ||
| 99 | + /** | ||
| 100 | + * @var Route $route | ||
| 101 | + */ | ||
| 102 | + foreach ($routes as $route) { | ||
| 103 | + if ($this->isMatch($route)) { | ||
| 104 | + $callback($this, $route); | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + /** | ||
| 110 | + * @param Route $route | ||
| 111 | + * @return bool | ||
| 112 | + */ | ||
| 113 | + protected function isMatch(Route $route): bool | ||
| 114 | + { | ||
| 115 | + if ($this->prefix && $prefixArray = explode(',', $this->prefix)) { | ||
| 116 | + if (!in_array($route->getPrefix(), $prefixArray)) { | ||
| 117 | + return false; | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + $action = $route->getAction(); | ||
| 122 | + | ||
| 123 | + if (!isset($action['controller'])) { | ||
| 124 | + return false; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + return true; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * @param Route $route | ||
| 132 | + * @return Doc | ||
| 133 | + * @throws \ReflectionException | ||
| 134 | + */ | ||
| 135 | + protected function resolveAnnotation(Route $route): Doc | ||
| 136 | + { | ||
| 137 | + Logger::writeln('parse ' . join('|', $route->methods()) . ' ' . $route->uri() . ' Annotation'); | ||
| 138 | + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); | ||
| 139 | + | ||
| 140 | + $refClass = new \ReflectionClass(($route->getController())); | ||
| 141 | + $method = $refClass->getMethod($route->getActionMethod()); | ||
| 142 | + | ||
| 143 | + $doc = new Doc(); | ||
| 144 | + | ||
| 145 | + foreach ($this->annotations as $annot) { | ||
| 146 | + | ||
| 147 | + Logger::writeln('parse ' . join('|', $route->methods()) . ' ' . $route->uri() . ' method annotation ' . $annot); | ||
| 148 | + | ||
| 149 | + $annotation = $reader->getMethodAnnotation($method, $annot); | ||
| 150 | + | ||
| 151 | + $pro = Str::camel(class_basename($annot)); | ||
| 152 | + | ||
| 153 | + if (!$annotation instanceof Annotation) { | ||
| 154 | + continue; | ||
| 155 | + } | ||
| 156 | + if (Str::endsWith($annot, 'Line')) { | ||
| 157 | + $doc->{$pro}[] = $annotation->toArray(); | ||
| 158 | + } else { | ||
| 159 | + $doc->{$pro} = $annotation->toArray(); | ||
| 160 | + } | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + return $doc; | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + /** | ||
| 167 | + * @return \Illuminate\Routing\RouteCollectionInterface|RouteCollection | ||
| 168 | + * @throws ContainerExceptionInterface | ||
| 169 | + * @throws NotFoundExceptionInterface | ||
| 170 | + */ | ||
| 171 | + protected function getRoutes() | ||
| 172 | + { | ||
| 173 | + /** | ||
| 174 | + * @var Router $router | ||
| 175 | + */ | ||
| 176 | + $router = $this->application->get('router'); | ||
| 177 | + | ||
| 178 | + return $router->getRoutes(); | ||
| 179 | + } | ||
| 180 | +} |
src/ShowDocGenerationServiceProvider.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration; | ||
| 4 | + | ||
| 5 | +use Illuminate\Support\ServiceProvider; | ||
| 6 | +use Lackoxygen\ShowDocGeneration\Commands\GenerationCommand; | ||
| 7 | + | ||
| 8 | +class ShowDocGenerationServiceProvider extends ServiceProvider | ||
| 9 | +{ | ||
| 10 | + public function boot() | ||
| 11 | + { | ||
| 12 | + if ($this->app->runningInConsole()) { | ||
| 13 | + $configPath = __DIR__ . '/../publish/doc.php'; | ||
| 14 | + $this->publishes([ | ||
| 15 | + $configPath => config_path('doc.php') | ||
| 16 | + ], 'lackoxygen-doc'); | ||
| 17 | + } | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + public function register() | ||
| 21 | + { | ||
| 22 | + $this->commands([ | ||
| 23 | + GenerationCommand::class | ||
| 24 | + ]); | ||
| 25 | + } | ||
| 26 | +} |
src/Writer/Client.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Writer; | ||
| 4 | + | ||
| 5 | +use GuzzleHttp\Exception\GuzzleException; | ||
| 6 | +use GuzzleHttp\RequestOptions; | ||
| 7 | +use Illuminate\Support\Arr; | ||
| 8 | +use Lackoxygen\ShowDocGeneration\Logger; | ||
| 9 | +use Lackoxygen\ShowDocGeneration\Parser\Doc; | ||
| 10 | + | ||
| 11 | +class Client | ||
| 12 | +{ | ||
| 13 | + protected \GuzzleHttp\Client $engine; | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * @var array | ||
| 17 | + */ | ||
| 18 | + protected array $config; | ||
| 19 | + | ||
| 20 | + public function __construct() | ||
| 21 | + { | ||
| 22 | + Logger::writeln('new GuzzleHttp\\Client'); | ||
| 23 | + $this->engine = new \GuzzleHttp\Client([ | ||
| 24 | + RequestOptions::TIMEOUT => 5.00 | ||
| 25 | + ]); | ||
| 26 | + | ||
| 27 | + $this->config = (array)config('doc', []); | ||
| 28 | + | ||
| 29 | + Logger::writeln('read doc config ' . \json_encode($this->config)); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * @param Doc $doc | ||
| 34 | + * @return void | ||
| 35 | + */ | ||
| 36 | + public function send(Doc $doc) | ||
| 37 | + { | ||
| 38 | + try { | ||
| 39 | + $params = [ | ||
| 40 | + 'api_key' => (string)Arr::get($this->config, 'api_key'), | ||
| 41 | + 'api_token' => (string)Arr::get($this->config, 'api_token'), | ||
| 42 | + 'cat_name' => Arr::get($doc->catalog, 'value', ''), | ||
| 43 | + 'page_title' => Arr::get($doc->title, 'value', ''), | ||
| 44 | + 'page_content' => (new Markdown($doc))->toString(), | ||
| 45 | + 's_number' => 99 | ||
| 46 | + ]; | ||
| 47 | + Logger::writeln('guzzle form params ' . json_encode($params, JSON_UNESCAPED_UNICODE)); | ||
| 48 | + $ret = $this->engine->post((string)Arr::get($this->config, 'api_url'), | ||
| 49 | + [ | ||
| 50 | + RequestOptions::FORM_PARAMS => $params | ||
| 51 | + ] | ||
| 52 | + ); | ||
| 53 | + Logger::writeln('guzzle status ' . $ret->getStatusCode()); | ||
| 54 | + Logger::writeln('guzzle response ' . \json_encode(\json_decode($ret->getBody()->getContents()), JSON_UNESCAPED_UNICODE)); | ||
| 55 | + } catch (GuzzleException $e) { | ||
| 56 | + Logger::writeln('guzzle error .' . $e->getMessage()); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | +} |
src/Writer/Markdown.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Writer; | ||
| 4 | + | ||
| 5 | +use Illuminate\Support\Arr; | ||
| 6 | +use Lackoxygen\ShowDocGeneration\Annotations\Method; | ||
| 7 | +use Lackoxygen\ShowDocGeneration\Parser\Doc; | ||
| 8 | + | ||
| 9 | +class Markdown | ||
| 10 | +{ | ||
| 11 | + protected string $template = <<<t | ||
| 12 | +##### 简要描述 | ||
| 13 | + | ||
| 14 | +- {{title}} | ||
| 15 | + | ||
| 16 | +##### 请求URL | ||
| 17 | +- ` {{url}} ` | ||
| 18 | + | ||
| 19 | +##### 请求方式 | ||
| 20 | +- {{method}} | ||
| 21 | + | ||
| 22 | +##### 参数 | ||
| 23 | +|参数名|必选|类型|说明| | ||
| 24 | +|:----|:---|:----- |-----| | ||
| 25 | +{{params}} | ||
| 26 | + | ||
| 27 | +##### 中间件 | ||
| 28 | +{{middles}} | ||
| 29 | + | ||
| 30 | +##### 请求头 | ||
| 31 | +|参数名|说明| | ||
| 32 | +|:---- |:---| | ||
| 33 | +{{headers}} | ||
| 34 | + | ||
| 35 | +##### 返回示例 | ||
| 36 | + | ||
| 37 | +``` | ||
| 38 | +{{resp}} | ||
| 39 | +``` | ||
| 40 | + | ||
| 41 | +##### 返回参数说明 | ||
| 42 | + | ||
| 43 | +|参数名|类型|说明| | ||
| 44 | +|:-----|:-----|:-----------------------------| | ||
| 45 | +{{respRemark}} | ||
| 46 | + | ||
| 47 | +##### 备注 | ||
| 48 | + | ||
| 49 | +- 最后更新时间:{{updateTime}} | ||
| 50 | +t; | ||
| 51 | + | ||
| 52 | + protected string $output = ''; | ||
| 53 | + | ||
| 54 | + public function __construct(Doc $doc) | ||
| 55 | + { | ||
| 56 | + $editTemplate = $this->template; | ||
| 57 | + | ||
| 58 | + $replaces = [ | ||
| 59 | + 'title' => Arr::get($doc->title, 'value'), | ||
| 60 | + 'url' => Arr::get($doc->url, 'path'), | ||
| 61 | + 'method' => Arr::get($doc->method, 'method', Method::METHOD_GET), | ||
| 62 | + 'headers' => join("\n", $this->tableTbody($doc->headerLine)), | ||
| 63 | + 'params' => join("\n", $this->tableTbody($doc->paramLine)), | ||
| 64 | + 'resp' => Arr::get($doc->resp, 'value', '{}'), | ||
| 65 | + 'respRemark' => join("\n", $this->tableTbody($doc->respLine)), | ||
| 66 | + 'middles' => join("\n", $this->unorderedList($doc->middles)), | ||
| 67 | + 'updateTime' => now()->toString() | ||
| 68 | + ]; | ||
| 69 | + | ||
| 70 | + $this->output = \str_replace( | ||
| 71 | + \array_map(function (string $key) { | ||
| 72 | + return '{{' . $key . '}}'; | ||
| 73 | + }, \array_keys($replaces)), | ||
| 74 | + \array_values($replaces), | ||
| 75 | + $editTemplate | ||
| 76 | + ); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + protected function unorderedList(array $list): array | ||
| 80 | + { | ||
| 81 | + return \array_map(function ($v) { | ||
| 82 | + return '- ' . $v; | ||
| 83 | + }, $list); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + protected function tableTbody(array $tbody): array | ||
| 87 | + { | ||
| 88 | + return \array_map(function (array $line) { | ||
| 89 | + $line = \array_map(function ($v) { | ||
| 90 | + if (\is_bool($v)) { | ||
| 91 | + $v = $v ? '是' : '否'; | ||
| 92 | + } | ||
| 93 | + return $v; | ||
| 94 | + }, $line); | ||
| 95 | + return '|' . \join('|', \array_values($line)) . '|'; | ||
| 96 | + }, $tbody); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + public function toString(): string | ||
| 100 | + { | ||
| 101 | + return $this->output; | ||
| 102 | + } | ||
| 103 | +} |
src/Writer/Writer.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Lackoxygen\ShowDocGeneration\Writer; | ||
| 4 | + | ||
| 5 | +use Illuminate\Support\Collection; | ||
| 6 | +use Lackoxygen\ShowDocGeneration\Parser\Doc; | ||
| 7 | + | ||
| 8 | +class Writer | ||
| 9 | +{ | ||
| 10 | + public function puts(Collection $docs) | ||
| 11 | + { | ||
| 12 | + $client = new Client(); | ||
| 13 | + | ||
| 14 | + $docs->each(function (Doc $doc) use ($client) { | ||
| 15 | + $client->send($doc); | ||
| 16 | + }); | ||
| 17 | + } | ||
| 18 | +} |
-
请 注册 或 登录 后发表评论