Browse Source

Merge branch 'master' into small-refactor-route-docblocker

Shalvah 4 năm trước cách đây
mục cha
commit
4b902ed172

+ 3 - 4
.travis.yml

@@ -10,12 +10,12 @@ env:
 matrix:
   fast_finish: true
   include:
-    - php: 7.4
-      env: COMPOSER=composer.dingo.json
-      name: "With Dingo router"
     - php: 7.4
       env: SETUP=lint
       name: "Lint code"
+    - php: 7.4
+      env: COMPOSER=composer.dingo.json
+      name: "With Dingo router"
     - php: 7.4.7
     - php: 7.4
       env: SETUP=lowest
@@ -31,7 +31,6 @@ before_install:
 install:
   - if [[ $SETUP = 'stable' ]]; then travis_retry composer update --prefer-dist --prefer-stable; fi
   - if [[ $SETUP = 'lowest' ]]; then travis_retry composer require laravel/framework:^$LOWEST; composer require laravel/lumen-framework:^$LOWEST; fi
-  - if [[ $SETUP = 'lint' ]]; then travis_retry composer update --prefer-dist --prefer-stable; composer lint; fi
 
 script:
   - if [[ $SETUP = 'lint' ]]; then exit 0; fi; composer test-parallel-ci;

+ 4 - 0
CHANGELOG.md

@@ -12,6 +12,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 
 ### Removals
 
+## 3.5.1 (Tuesday, 6 July 2021)
+### Fixed
+- Try It Out: Turn off autocomplete; make sure it works for array body; improve UI spacing ([579f672b57ad0417a5563aee1621b84c3b4ff1f2](https://github.com/knuckleswtf/scribe/commit/579f672b57ad0417a5563aee1621b84c3b4ff1f2), [2af8d8eacd661e0601b2d6f4dbc1766bf75e702a](https://github.com/knuckleswtf/scribe/commit/2af8d8eacd661e0601b2d6f4dbc1766bf75e702a))
+
 ## 3.5.0 (Monday, 5 July 2021)
 ### Modified
 - Get URL parameter name from field bindings (https://github.com/knuckleswtf/scribe/commit/ce6be7ca68ed0e682258eca5bbeb2f7d84774714)

+ 6 - 0
camel/Output/OutputEndpointData.php

@@ -150,6 +150,12 @@ class OutputEndpointData extends BaseDTO
         return count($this->fileParameters) > 0;
     }
 
+    public function isArrayBody(): bool
+    {
+        return count($this->nestedBodyParameters) === 1
+            && array_keys($this->nestedBodyParameters)[0] === "[]";
+    }
+
     public function isGet(): bool
     {
         return in_array('GET', $this->httpMethods);

+ 1 - 1
resources/css/theme-default.style.css

@@ -858,7 +858,7 @@ html {
 .content pre {
     background-color: #292929;
     color: #fff;
-    padding: 2em 28px;
+    padding: 1.5em 28px;
     margin: 0;
     width: 50%;
     float: right;

+ 7 - 4
resources/js/tryitout.js

@@ -142,12 +142,15 @@ async function executeTryOut(endpointId, form) {
 
     let body;
     let setter;
-    if (form.dataset.hasfiles === "0") {
-        body = {};
-        setter = (name, value) => _.set(body, name, value);
-    } else {
+    if (form.dataset.hasfiles === "1") {
         body = new FormData();
         setter = (name, value) => body.append(name, value);
+    } else if (form.dataset.isarraybody === "1") {
+        body = [];
+        setter = (name, value) => _.set(body, name, value);
+    } else {
+        body = {};
+        setter = (name, value) => _.set(body, name, value);
     }
     const bodyParameters = form.querySelectorAll('input[data-component=body]');
     bodyParameters.forEach(el => {

+ 2 - 0
resources/views/components/field-details.blade.php

@@ -10,6 +10,8 @@
             $fullName .= '.0';
             $baseType = substr($baseType, 0, -2);
         }
+        // When the body is an array, the item names will be ".0.thing"
+        $fullName = ltrim($fullName, '.');
         switch($baseType) {
             case 'number':
             case 'integer':

+ 8 - 10
resources/views/themes/default/endpoint.blade.php

@@ -32,24 +32,20 @@
             <summary>
                 <small onclick="textContent = parentElement.parentElement.open ? 'Show headers' : 'Hide headers'">Show headers</small>
             </summary>
-            <pre>
-            <code class="language-http">@foreach($response->headers as $header => $value)
+            <pre><code class="language-http">@foreach($response->headers as $header => $value)
 {{ $header }}: {{ is_array($value) ? implode('; ', $value) : $value }}
-@endforeach </code>
-            </pre>
+@endforeach </code></pre>
         </details> @endif
         <pre>
-                <code class="language-json">
 @if(is_string($response->content) && Str::startsWith($response->content, "<<binary>>"))
-[Binary data] - {{ htmlentities(str_replace("<<binary>>", "", $response->content)) }}
+<code>[Binary data] - {{ htmlentities(str_replace("<<binary>>", "", $response->content)) }}</code>
 @elseif($response->status == 204)
-[Empty response]
+<code>[Empty response]</code>
 @else
 @php($parsed = json_decode($response->content))
 {{-- If response is a JSON string, prettify it. Otherwise, just print it --}}
-{!! htmlentities($parsed != null ? json_encode($parsed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) : $response->content) !!}
-@endif </code>
-        </pre>
+<code class="language-json">{!! htmlentities($parsed != null ? json_encode($parsed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) : $response->content) !!}</code>
+@endif </pre>
     @endforeach
 @endif
 </span>
@@ -67,7 +63,9 @@
       data-path="{{ $endpoint->uri }}"
       data-authed="{{ $endpoint->metadata->authenticated ? 1 : 0 }}"
       data-hasfiles="{{ $endpoint->hasFiles() ? 1 : 0 }}"
+      data-isarraybody="{{ $endpoint->isArrayBody() ? 1 : 0 }}"
       data-headers='@json($endpoint->headers)'
+      autocomplete="off"
       onsubmit="event.preventDefault(); executeTryOut('{{ $endpoint->endpointId() }}', this);">
     <h3>
         Request&nbsp;&nbsp;&nbsp;

+ 1 - 1
src/Commands/GenerateDocumentation.php

@@ -84,7 +84,7 @@ class GenerateDocumentation extends Command
             throw new \Exception("Can't use --force and --no-extraction together.");
         }
 
-        // Reset this map useful for tests)
+        // Reset this map (useful for tests)
         Camel::$groupFileNames = [];
     }
 

+ 1 - 1
src/Extracting/Strategies/Headers/GetFromHeaderTag.php

@@ -56,7 +56,7 @@ class GetFromHeaderTag extends Strategy
         return $this->getHeadersFromDocBlock($methodDocBlock->getTags());
     }
 
-    public function getHeadersFromDocBlock($tags)
+    public function getHeadersFromDocBlock($tags): array
     {
         $headers = collect($tags)
             ->filter(function ($tag) {

+ 1 - 1
src/Tools/Globals.php

@@ -4,7 +4,7 @@ namespace Knuckles\Scribe\Tools;
 
 class Globals
 {
-    public const SCRIBE_VERSION = '3.5.0';
+    public const SCRIBE_VERSION = '3.5.1';
 
     public static bool $shouldBeVerbose = false;
 }

+ 34 - 10
tests/GenerateDocumentationTest.php

@@ -22,6 +22,9 @@ class GenerateDocumentationTest extends BaseLaravelTest
         parent::setUp();
 
         config(['scribe.database_connections_to_transact' => []]);
+        // Skip these ones for faster tests
+        config(['scribe.openapi.enabled' => false]);
+        config(['scribe.postman.enabled' => false]);
 
         $factory = app(\Illuminate\Database\Eloquent\Factory::class);
         $factory->define(TestUser::class, function () {
@@ -206,7 +209,6 @@ class GenerateDocumentationTest extends BaseLaravelTest
             ],
         ]);
         config(['scribe.postman.enabled' => true]);
-        config(['scribe.openapi.enabled' => false]);
 
         $this->artisan('scribe:generate');
 
@@ -230,7 +232,6 @@ class GenerateDocumentationTest extends BaseLaravelTest
 
         // We want to have the same values for params each time
         config(['scribe.faker_seed' => 1234]);
-        config(['scribe.postman.enabled' => false]);
         config(['scribe.openapi.enabled' => true]);
         config(['scribe.openapi.overrides' => [
             'info.version' => '3.9.9',
@@ -372,8 +373,6 @@ class GenerateDocumentationTest extends BaseLaravelTest
             ]);
         });
         config(['scribe.routes.0.match.prefixes' => ['*']]);
-        config(['scribe.openapi.enabled' => false]);
-        config(['scribe.postman.enabled' => false]);
 
         $this->artisan('scribe:generate');
 
@@ -387,8 +386,6 @@ class GenerateDocumentationTest extends BaseLaravelTest
     public function will_not_extract_if_noExtraction_flag_is_set()
     {
         config(['scribe.routes.0.exclude' => ['*']]);
-        config(['scribe.openapi.enabled' => false]);
-        config(['scribe.postman.enabled' => false]);
         Utils::copyDirectory(__DIR__.'/Fixtures/.scribe', '.scribe');
 
         $output = $this->artisan('scribe:generate', ['--no-extraction' => true]);
@@ -412,8 +409,6 @@ class GenerateDocumentationTest extends BaseLaravelTest
         RouteFacade::get('/api/action1', [TestGroupController::class, 'action1']);
         RouteFacade::get('/api/action2', [TestGroupController::class, 'action2']);
         config(['scribe.routes.0.match.prefixes' => ['api/*']]);
-        config(['scribe.openapi.enabled' => false]);
-        config(['scribe.postman.enabled' => false]);
         if (!is_dir('.scribe/endpoints'))
             mkdir('.scribe/endpoints', 0777, true);
         copy(__DIR__ . '/Fixtures/custom.0.yaml', '.scribe/endpoints/custom.0.yaml');
@@ -443,8 +438,6 @@ class GenerateDocumentationTest extends BaseLaravelTest
         RouteFacade::get('/api/action1b', [TestGroupController::class, 'action1b']);
         RouteFacade::get('/api/action2', [TestGroupController::class, 'action2']);
         config(['scribe.routes.0.match.prefixes' => ['api/*']]);
-        config(['scribe.openapi.enabled' => false]);
-        config(['scribe.postman.enabled' => false]);
 
         $this->artisan('scribe:generate');
 
@@ -485,4 +478,35 @@ class GenerateDocumentationTest extends BaseLaravelTest
         $this->assertEquals("Another endpoint.", $expectedEndpoints->getNode(1)->textContent);
         $this->assertEquals("Some endpoint.", $expectedEndpoints->getNode(2)->textContent);
     }
+
+    /** @test */
+    public function will_auto_set_content_type_to_multipart_if_file_params_are_present()
+    {
+        /**
+         * @bodyParam param string required
+         */
+        RouteFacade::post('no-file', fn() => null);
+        /**
+         * @bodyParam a_file file required
+         */
+        RouteFacade::post('top-level-file', fn() => null);
+        /**
+         * @bodyParam data object
+         * @bodyParam data.thing string
+         * @bodyParam data.a_file file
+         */
+        RouteFacade::post('nested-file', fn() => null);
+        config(['scribe.routes.0.match.prefixes' => ['*']]);
+
+        $this->artisan('scribe:generate');
+
+        $group = Yaml::parseFile('.scribe/endpoints/0.yaml');
+        $this->assertEquals('no-file', $group['endpoints'][0]['uri']);
+        $this->assertEquals('application/json', $group['endpoints'][0]['headers']['Content-Type']);
+        $this->assertEquals('top-level-file', $group['endpoints'][1]['uri']);
+        $this->assertEquals('multipart/form-data', $group['endpoints'][1]['headers']['Content-Type']);
+        $this->assertEquals('nested-file', $group['endpoints'][2]['uri']);
+        $this->assertEquals('multipart/form-data', $group['endpoints'][2]['headers']['Content-Type']);
+
+    }
 }