From ad39ff93e9f9d87fe9b25f1441133e14c9c79079 Mon Sep 17 00:00:00 2001 From: shalvah Date: Sat, 15 Sep 2018 15:15:24 +0100 Subject: [PATCH 1/6] Code style fixes --- .../ApiDoc/Commands/GenerateDocumentation.php | 14 +++----------- .../ApiDoc/Generators/AbstractGenerator.php | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php b/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php index 7428fd40..8b1af9b5 100644 --- a/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php +++ b/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php @@ -89,17 +89,9 @@ public function handle() $parsedRoutes = []; - if ($this->option('router') === 'laravel') { - foreach ($routeDomains as $routeDomain) { - foreach ($routePrefixes as $routePrefix) { - $parsedRoutes += $this->processRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware); - } - } - } else { - foreach ($routeDomains as $routeDomain) { - foreach ($routePrefixes as $routePrefix) { - $parsedRoutes += $this->processDingoRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware); - } + foreach ($routeDomains as $routeDomain) { + foreach ($routePrefixes as $routePrefix) { + $parsedRoutes += $this->processRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware); } } $parsedRoutes = collect($parsedRoutes)->groupBy('resource')->sort(function ($a, $b) { diff --git a/src/Mpociot/ApiDoc/Generators/AbstractGenerator.php b/src/Mpociot/ApiDoc/Generators/AbstractGenerator.php index 1870f7e5..7404d844 100644 --- a/src/Mpociot/ApiDoc/Generators/AbstractGenerator.php +++ b/src/Mpociot/ApiDoc/Generators/AbstractGenerator.php @@ -168,7 +168,7 @@ protected function getParameters($routeData, $routeAction, $bindings) } /** - * Format the validation rules as plain array. + * Format the validation rules as a plain array. * * @param array $rules * From dde13fdc68e266b2221c74c3029146a969208fa3 Mon Sep 17 00:00:00 2001 From: shalvah Date: Sat, 15 Sep 2018 17:59:25 +0100 Subject: [PATCH 2/6] Code style tweaks --- .../ApiDoc/Generators/AbstractGenerator.php | 30 +++++++++++-------- tests/RuleDescriptionParserTest.php | 4 +-- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/Mpociot/ApiDoc/Generators/AbstractGenerator.php b/src/Mpociot/ApiDoc/Generators/AbstractGenerator.php index 7404d844..2f2a21c1 100644 --- a/src/Mpociot/ApiDoc/Generators/AbstractGenerator.php +++ b/src/Mpociot/ApiDoc/Generators/AbstractGenerator.php @@ -148,7 +148,8 @@ protected function getDocblockResponse($tags) */ protected function getParameters($routeData, $routeAction, $bindings) { - $rules = $this->simplifyRules($this->getRouteRules($routeData['methods'], $routeAction['uses'], $bindings)); + $validationRules = $this->getRouteValidationRules($routeData['methods'], $routeAction['uses'], $bindings); + $rules = $this->simplifyRules($validationRules); foreach ($rules as $attribute => $ruleset) { $attributeData = [ @@ -176,19 +177,24 @@ protected function getParameters($routeData, $routeAction, $bindings) */ protected function simplifyRules($rules) { - $simplifiedRules = Validator::make([], $rules)->getRules(); + // this will split all string rules into arrays of strings + $rules = Validator::make([], $rules)->getRules(); - if (count($simplifiedRules) === 0) { - return $simplifiedRules; + if (count($rules) === 0) { + return $rules; } - $values = collect($simplifiedRules) + // Laravel will ignore the nested array rules unless the key referenced exists and is an array + // So we'll to create an empty array for each array attribute + $values = collect($rules) ->filter(function ($values) { return in_array('array', $values); })->map(function ($val, $key) { return ['']; })->all(); + // Now this will return the complete ruleset. + // Nested array parameters will be present, with '*' replaced by '0' return Validator::make($values, $rules)->getRules(); } @@ -287,10 +293,10 @@ protected function getRouteGroup($route) * * @return array */ - protected function getRouteRules(array $routeMethods, $routeAction, $bindings) + protected function getRouteValidationRules(array $routeMethods, $routeAction, $bindings) { - list($class, $method) = explode('@', $routeAction); - $reflection = new ReflectionClass($class); + list($controller, $method) = explode('@', $routeAction); + $reflection = new ReflectionClass($controller); $reflectionMethod = $reflection->getMethod($method); foreach ($reflectionMethod->getParameters() as $parameter) { @@ -357,13 +363,13 @@ protected function splitValuePairs($parameters, $first = 'is ', $last = 'or ') /** * @param string $rule - * @param string $ruleName + * @param string $attribute * @param array $attributeData * @param int $seed * * @return void */ - protected function parseRule($rule, $ruleName, &$attributeData, $seed, $routeData) + protected function parseRule($rule, $attribute, &$attributeData, $seed, $routeData) { $faker = Factory::create(); $faker->seed(crc32($seed)); @@ -510,7 +516,7 @@ protected function parseRule($rule, $ruleName, &$attributeData, $seed, $routeDat $attributeData['value'] = $faker->timezone; break; case 'exists': - $fieldName = isset($parameters[1]) ? $parameters[1] : $ruleName; + $fieldName = isset($parameters[1]) ? $parameters[1] : $attribute; $attributeData['description'][] = Description::parse($rule)->with([Str::singular($parameters[0]), $fieldName])->getDescription(); break; case 'active_url': @@ -627,7 +633,7 @@ protected function parseStringRule($rules) // The format for specifying validation rules and parameters follows an // easy {rule}:{parameters} formatting convention. For instance the - // rule "Max:3" states that the value may only be three letters. + // rule "max:3" states that the value may only be three letters. if (strpos($rules, ':') !== false) { list($rules, $parameter) = explode(':', $rules, 2); diff --git a/tests/RuleDescriptionParserTest.php b/tests/RuleDescriptionParserTest.php index 1281bdaf..f1f6f724 100644 --- a/tests/RuleDescriptionParserTest.php +++ b/tests/RuleDescriptionParserTest.php @@ -112,7 +112,7 @@ protected function getPackageProviders($app) */ protected function getEnvironmentSetUp($app) { - $app['config']->set('app.locale', 'es'); // Just to be different to default language. - $app['config']->set('app.fallback_locale', 'ch'); // Just to be different to default language. + $app['config']->set('app.locale', 'es'); // Just to be different from default language. + $app['config']->set('app.fallback_locale', 'ch'); // Just to be different from default language. } } From fae5fd142f2851999ba422bd33a50c435866c010 Mon Sep 17 00:00:00 2001 From: shalvah Date: Sat, 15 Sep 2018 20:46:57 +0100 Subject: [PATCH 3/6] Fix formatting issues with generated markdown (Fixes #191) --- src/resources/views/partials/route.blade.php | 9 ++++---- tests/Fixtures/index.md | 8 +++---- tests/Fixtures/resource_index.md | 22 ++++++++++---------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/resources/views/partials/route.blade.php b/src/resources/views/partials/route.blade.php index 8803b0c1..02e340a6 100644 --- a/src/resources/views/partials/route.blade.php +++ b/src/resources/views/partials/route.blade.php @@ -10,10 +10,11 @@ > Example request: ```bash -curl -X {{$parsedRoute['methods'][0]}} "{{ trim(config('app.docs_url') ?: config('app.url'), '/')}}/{{ ltrim($parsedRoute['uri'], '/') }}" \ --H "Accept: application/json"@if(count($parsedRoute['parameters'])) \ +curl -X {{$parsedRoute['methods'][0]}} {{$parsedRoute['methods'][0] == 'GET' ? '-G ' : ''}}"{{ trim(config('app.docs_url') ?: config('app.url'), '/')}}/{{ ltrim($parsedRoute['uri'], '/') }}" \ + -H "Accept: application/json"@if(count($parsedRoute['parameters'])) \ @foreach($parsedRoute['parameters'] as $attribute => $parameter) - -d "{{$attribute}}"="{{$parameter['value']}}" \ + -d "{{$attribute}}"="{{$parameter['value']}}" @if(! ($loop->last))\ + @endif @endforeach @endif @@ -26,7 +27,7 @@ "url": "{{ rtrim(config('app.docs_url') ?: config('app.url'), '/') }}/{{ ltrim($parsedRoute['uri'], '/') }}", "method": "{{$parsedRoute['methods'][0]}}", @if(count($parsedRoute['parameters'])) -"data": {!! str_replace(' ',' ',json_encode(array_combine(array_keys($parsedRoute['parameters']), array_map(function($param){ return $param['value']; },$parsedRoute['parameters'])), JSON_PRETTY_PRINT)) !!}, +"data": {!! str_replace("\n}","\n }", str_replace(' ',' ',json_encode(array_combine(array_keys($parsedRoute['parameters']), array_map(function($param){ return $param['value']; },$parsedRoute['parameters'])), JSON_PRETTY_PRINT))) !!}, @endif "headers": { "accept": "application/json" diff --git a/tests/Fixtures/index.md b/tests/Fixtures/index.md index f34641d4..57d0b130 100644 --- a/tests/Fixtures/index.md +++ b/tests/Fixtures/index.md @@ -30,8 +30,8 @@ It can also be multiple lines long. > Example request: ```bash -curl -X GET "http://localhost/api/test" \ --H "Accept: application/json" +curl -X GET -G "http://localhost/api/test" \ + -H "Accept: application/json" ``` ```javascript @@ -68,8 +68,8 @@ null > Example request: ```bash -curl -X GET "http://localhost/api/fetch" \ --H "Accept: application/json" +curl -X GET -G "http://localhost/api/fetch" \ + -H "Accept: application/json" ``` ```javascript diff --git a/tests/Fixtures/resource_index.md b/tests/Fixtures/resource_index.md index 027c3b6a..2a98f7c9 100644 --- a/tests/Fixtures/resource_index.md +++ b/tests/Fixtures/resource_index.md @@ -27,8 +27,8 @@ Welcome to the generated API reference. > Example request: ```bash -curl -X GET "http://localhost/api/user" \ --H "Accept: application/json" +curl -X GET -G "http://localhost/api/user" \ + -H "Accept: application/json" ``` ```javascript @@ -67,8 +67,8 @@ $.ajax(settings).done(function (response) { > Example request: ```bash -curl -X GET "http://localhost/api/user/create" \ --H "Accept: application/json" +curl -X GET -G "http://localhost/api/user/create" \ + -H "Accept: application/json" ``` ```javascript @@ -108,7 +108,7 @@ $.ajax(settings).done(function (response) { ```bash curl -X POST "http://localhost/api/user" \ --H "Accept: application/json" + -H "Accept: application/json" ``` ```javascript @@ -140,8 +140,8 @@ $.ajax(settings).done(function (response) { > Example request: ```bash -curl -X GET "http://localhost/api/user/{user}" \ --H "Accept: application/json" +curl -X GET -G "http://localhost/api/user/{user}" \ + -H "Accept: application/json" ``` ```javascript @@ -180,8 +180,8 @@ $.ajax(settings).done(function (response) { > Example request: ```bash -curl -X GET "http://localhost/api/user/{user}/edit" \ --H "Accept: application/json" +curl -X GET -G "http://localhost/api/user/{user}/edit" \ + -H "Accept: application/json" ``` ```javascript @@ -221,7 +221,7 @@ $.ajax(settings).done(function (response) { ```bash curl -X PUT "http://localhost/api/user/{user}" \ --H "Accept: application/json" + -H "Accept: application/json" ``` ```javascript @@ -256,7 +256,7 @@ $.ajax(settings).done(function (response) { ```bash curl -X DELETE "http://localhost/api/user/{user}" \ --H "Accept: application/json" + -H "Accept: application/json" ``` ```javascript From d5bbd7b94ecbddb32c0a9e8f1556e3da24d1187f Mon Sep 17 00:00:00 2001 From: shalvah Date: Sat, 15 Sep 2018 21:10:23 +0100 Subject: [PATCH 4/6] Add support for appending/prepending markdown content (closes #262) --- README.md | 7 +++++++ src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php | 11 +++++++++++ src/resources/views/documentarian.blade.php | 8 ++++---- tests/Fixtures/index.md | 1 + tests/Fixtures/resource_index.md | 1 + tests/GenerateDocumentationTest.php | 4 ++-- 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2b6b8e87..0c9f0868 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,13 @@ $ php artisan api:update As an optional parameter, you can use `--location` to tell the update command where your documentation can be found. +## Automatically add markdown to the beginning or end of the documentation + If you wish to automatically add the same content to the docs every time you generate, you can add a `prepend.md` and/or `append.md` file to the source folder, and they will be included above and below the generated documentation. + + **File locations:** +- `public/docs/source/prepend.md` +- `public/docs/source/append.md` + ## Skip single routes If you want to skip a single route from a list of routes that match a given prefix, you can use the `@hideFromAPIDocumentation` tag on the Controller method you do not want to document. diff --git a/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php b/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php index 8b1af9b5..98027124 100644 --- a/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php +++ b/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php @@ -111,6 +111,8 @@ private function writeMarkdown($parsedRoutes) $outputPath = $this->option('output'); $targetFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'index.md'; $compareFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'.compare.md'; + $prependFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'prepend.md'; + $appendFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'append.md'; $infoText = view('apidoc::partials.info') ->with('outputPath', ltrim($outputPath, 'public/')) @@ -156,12 +158,19 @@ private function writeMarkdown($parsedRoutes) }); } + $prependFileContents = file_exists($prependFile) + ?file_get_contents($prependFile)."\n" : ''; + $appendFileContents = file_exists($appendFile) + ? "\n".file_get_contents($appendFile) : ''; + $documentarian = new Documentarian(); $markdown = view('apidoc::documentarian') ->with('writeCompareFile', false) ->with('frontmatter', $frontmatter) ->with('infoText', $infoText) + ->with('prependMd', $prependFileContents) + ->with('appendMd', $appendFileContents) ->with('outputPath', $this->option('output')) ->with('showPostmanCollectionButton', ! $this->option('noPostmanCollection')) ->with('parsedRoutes', $parsedRouteOutput); @@ -178,6 +187,8 @@ private function writeMarkdown($parsedRoutes) ->with('writeCompareFile', true) ->with('frontmatter', $frontmatter) ->with('infoText', $infoText) + ->with('prependMd', $prependFileContents) + ->with('appendMd', $appendFileContents) ->with('outputPath', $this->option('output')) ->with('showPostmanCollectionButton', ! $this->option('noPostmanCollection')) ->with('parsedRoutes', $parsedRouteOutput); diff --git a/src/resources/views/documentarian.blade.php b/src/resources/views/documentarian.blade.php index 6d7a3c24..d1bb3463 100644 --- a/src/resources/views/documentarian.blade.php +++ b/src/resources/views/documentarian.blade.php @@ -4,16 +4,16 @@ {!! $infoText !!} - +{!! $prependMd !!} @foreach($parsedRoutes as $group => $routes) @if($group) #{!! $group !!} @endif @foreach($routes as $parsedRoute) @if($writeCompareFile === true) -{!! $parsedRoute['output']!!} +{!! $parsedRoute['output'] !!} @else -{!! isset($parsedRoute['modified_output']) ? $parsedRoute['modified_output'] : $parsedRoute['output']!!} +{!! isset($parsedRoute['modified_output']) ? $parsedRoute['modified_output'] : $parsedRoute['output'] !!} @endif @endforeach -@endforeach +@endforeach{!! $appendMd !!} diff --git a/tests/Fixtures/index.md b/tests/Fixtures/index.md index 57d0b130..14b0648e 100644 --- a/tests/Fixtures/index.md +++ b/tests/Fixtures/index.md @@ -106,3 +106,4 @@ $.ajax(settings).done(function (response) { + diff --git a/tests/Fixtures/resource_index.md b/tests/Fixtures/resource_index.md index 2a98f7c9..c4b4676f 100644 --- a/tests/Fixtures/resource_index.md +++ b/tests/Fixtures/resource_index.md @@ -282,3 +282,4 @@ $.ajax(settings).done(function (response) { + diff --git a/tests/GenerateDocumentationTest.php b/tests/GenerateDocumentationTest.php index d4ec3274..ab8fdf94 100644 --- a/tests/GenerateDocumentationTest.php +++ b/tests/GenerateDocumentationTest.php @@ -123,8 +123,8 @@ public function testCanParseResourceRoutes() '--routePrefix' => 'api/*', ]); $fixtureMarkdown = __DIR__.'/Fixtures/resource_index.md'; - $gneratedMarkdown = __DIR__.'/../public/docs/source/index.md'; - $this->assertFilesHaveSameContent($fixtureMarkdown, $gneratedMarkdown); + $generatedMarkdown = __DIR__.'/../public/docs/source/index.md'; + $this->assertFilesHaveSameContent($fixtureMarkdown, $generatedMarkdown); } public function testGeneratedMarkdownFileIsCorrect() From fcd6f350f5a1f0feaea362efd54c640f891eac5f Mon Sep 17 00:00:00 2001 From: shalvah Date: Sat, 15 Sep 2018 21:13:12 +0100 Subject: [PATCH 5/6] Fix style --- src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php b/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php index 98027124..0ac2dff2 100644 --- a/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php +++ b/src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php @@ -159,7 +159,7 @@ private function writeMarkdown($parsedRoutes) } $prependFileContents = file_exists($prependFile) - ?file_get_contents($prependFile)."\n" : ''; + ? file_get_contents($prependFile)."\n" : ''; $appendFileContents = file_exists($appendFile) ? "\n".file_get_contents($appendFile) : ''; From 70c0cda1cfd3d1ded22f36abe535d5cfe414191d Mon Sep 17 00:00:00 2001 From: shalvah Date: Sun, 16 Sep 2018 10:13:35 +0100 Subject: [PATCH 6/6] Add tests for prependinf and appending markdown (#191) --- README.md | 4 ++-- tests/Fixtures/append.md | 3 +++ tests/Fixtures/prepend.md | 3 +++ tests/GenerateDocumentationTest.php | 23 +++++++++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/Fixtures/append.md create mode 100644 tests/Fixtures/prepend.md diff --git a/README.md b/README.md index 0c9f0868..bb74d947 100644 --- a/README.md +++ b/README.md @@ -244,8 +244,8 @@ As an optional parameter, you can use `--location` to tell the update command wh If you wish to automatically add the same content to the docs every time you generate, you can add a `prepend.md` and/or `append.md` file to the source folder, and they will be included above and below the generated documentation. **File locations:** -- `public/docs/source/prepend.md` -- `public/docs/source/append.md` +- `public/docs/source/prepend.md` - Will be added after the front matter and info text +- `public/docs/source/append.md` - Will be added at the end of the document ## Skip single routes diff --git a/tests/Fixtures/append.md b/tests/Fixtures/append.md new file mode 100644 index 00000000..6da749a1 --- /dev/null +++ b/tests/Fixtures/append.md @@ -0,0 +1,3 @@ +# Appended Markdown + +This markdown should be added to the end of generated docs diff --git a/tests/Fixtures/prepend.md b/tests/Fixtures/prepend.md new file mode 100644 index 00000000..0b7899f0 --- /dev/null +++ b/tests/Fixtures/prepend.md @@ -0,0 +1,3 @@ +# Prepended Markdown + +This markdown should be added to the start of generated docs diff --git a/tests/GenerateDocumentationTest.php b/tests/GenerateDocumentationTest.php index ab8fdf94..836200c8 100644 --- a/tests/GenerateDocumentationTest.php +++ b/tests/GenerateDocumentationTest.php @@ -143,6 +143,29 @@ public function testGeneratedMarkdownFileIsCorrect() $this->assertFilesHaveSameContent($fixtureMarkdown, $compareMarkdown); } + public function testCanPrependAndAppendDataToGeneratedMarkdown() + { + RouteFacade::get('/api/test', TestController::class.'@parseMethodDescription'); + RouteFacade::get('/api/fetch', TestController::class.'@fetchRouteResponse'); + + $this->artisan('api:generate', [ + '--routePrefix' => 'api/*', + ]); + + $prependMarkdown = __DIR__.'/Fixtures/prepend.md'; + $appendMarkdown = __DIR__.'/Fixtures/append.md'; + copy($prependMarkdown, __DIR__.'/../public/docs/source/prepend.md'); + copy($appendMarkdown, __DIR__.'/../public/docs/source/append.md'); + + $this->artisan('api:generate', [ + '--routePrefix' => 'api/*', + ]); + + $generatedMarkdown = __DIR__.'/../public/docs/source/index.md'; + $this->assertContainsRaw($this->getFileContents($prependMarkdown), $this->getFileContents($generatedMarkdown)); + $this->assertContainsRaw($this->getFileContents($appendMarkdown), $this->getFileContents($generatedMarkdown)); + } + public function testAddsBindingsToGetRouteRules() { RouteFacade::get('/api/test/{foo}', TestController::class.'@addRouteBindingsToRequestClass');