Docs codeblocks (#1232)

Add custom theme code to add annotations/attributes tabs to code examples.
This commit is contained in:
Martin Rademacher 2022-05-19 12:13:01 +12:00 committed by GitHub
parent 4087d4fe5b
commit 117caa0c0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 287 additions and 58 deletions

View File

@ -4,8 +4,9 @@ on:
workflow_dispatch:
inputs:
dryrun:
type: boolean
description: Dry run
type: boolean
required: false
jobs:
gh-pages:
@ -23,11 +24,11 @@ jobs:
with:
dependency-versions: 'highest'
- name: Install vitepress
run: cd docs && npm install vitepress
- name: Install vitepress and deps
run: cd docs && npm install
- name: Build site
run: cd docs && php refgen.php && npm run build
run: composer docs:build
- name: Deploy to GitHub Pages
if: success()

View File

@ -134,6 +134,11 @@ composer test
./bin/phpunit
```
### Regenerate annotation/attribute reference markup docs
```bash
composer docs:refgen
```
### Running linting only:
```bash
composer lint

View File

@ -73,6 +73,18 @@
"OpenApi\\Tests\\Fixtures\\Annotations\\": "tests/Fixtures/Annotations"
}
},
"scripts-descriptions": {
"cs": "Fix all codestyle issues",
"lint": "Test codestyle",
"test": "Run all non-legacy and codestyle tests",
"testlegacy": "Run tests using the legacy TokenAnalyser",
"testall": "Run all tests (test + testlegacy)",
"analyse": "Run static analysis (phpstan/psalm)",
"spectral": "Run spectral lint over all .yaml files in the Examples folder",
"docs:refgen": "Rebuild the annotations/attributes reference markup files",
"docs:dev": "Run dev server for local development of gh-pages",
"docs:build": "Re-build static gh-pages"
},
"scripts": {
"cs": "php-cs-fixer fix --allow-risky=yes",
"lint": "@cs --dry-run",
@ -90,8 +102,11 @@
"psalm"
],
"spectral": "for ff in `find Examples -name '*.yaml'`; do spectral lint $ff; done",
"docs:refgen": "php docs/refgen.php",
"docs:dev": "cd docs && npm run dev",
"docs:build": "cd docs && php refgen.php && npm run build",
"docs:deploy": "cd docs && npm run deploy"
"docs:build": [
"@docs:refgen",
"cd docs && npm run build"
]
}
}

View File

@ -0,0 +1,31 @@
<template>
<div>
<tabs :options="{ useUrlFragment: false }">
<tab :id="anId" name="Annotations">
<slot name="an"></slot>
</tab>
<tab :id="atId" name="Attributes">
<slot name="at"></slot>
</tab>
</tabs>
</div>
</template>
<script>
export default {
props: {
id: {
type: String,
default: null
}
},
computed: {
anId() {
return this.id + '-an'
},
atId() {
return this.id + '-at'
}
}
}
</script>

View File

@ -0,0 +1,30 @@
/* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */
:root {
--c-brand: #74a535;
--c-brand-light: #94c73d;
--c-bg: #fefefe;
}
.tabs-component {
margin: 2em 0;
}
.tabs-component-panels {
padding: 0 0;
border: none;
}
.tabs-component-tab-a {
padding: 0.5em;
}
.tabs-component-tab {
transform: none;
}
@media (min-width: 700px) {
.tabs-component-tab.is-active {
border-bottom: solid 1px #ddd;
}
}

View File

@ -0,0 +1,14 @@
import DefaultTheme from "vitepress/theme";
import {Tabs, Tab} from 'vue3-tabs-component';
import Codeblock from "./components/Codeblock.vue";
import "./tabs.css";
import "./custom.css";
export default {
...DefaultTheme,
enhanceApp({ app, router, siteData }) {
app.component('tabs', Tabs);
app.component('tab', Tab);
app.component('codeblock', Codeblock);
},
};

View File

@ -0,0 +1,80 @@
.tabs-component {
margin: 2em 0;
}
.tabs-component-tabs {
border: solid 1px #ddd;
border-radius: 6px;
margin-bottom: 5px;
}
@media (min-width: 700px) {
.tabs-component-tabs {
border: 0;
align-items: stretch;
display: flex;
justify-content: flex-start;
margin-bottom: -1px;
}
}
.tabs-component-tab {
color: #999;
font-size: 14px;
font-weight: 600;
margin-right: 0;
list-style: none;
}
.tabs-component-tab:hover {
color: #666;
}
.tabs-component-tab.is-active {
color: #000;
}
.tabs-component-tab.is-disabled * {
color: #cdcdcd;
cursor: not-allowed !important;
}
@media (min-width: 700px) {
.tabs-component-tab {
background-color: #fff;
border: solid 1px #ddd;
border-radius: 3px 3px 0 0;
margin-right: 0.5em;
transform: translateY(2px);
transition: transform 0.3s ease;
}
.tabs-component-tab.is-active {
border-bottom: solid 1px #fff;
z-index: 2;
transform: translateY(0);
}
}
.tabs-component-tab-a {
align-items: center;
color: inherit;
display: flex;
padding: 0.5em 1.25em;
text-decoration: none;
}
.tabs-component-panels {
padding: 1em 0;
}
@media (min-width: 700px) {
.tabs-component-panels {
background-color: #fff;
border: solid 1px #ddd;
border-radius: 6px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
padding: 1em 1em;
position: relative;
}
}

View File

@ -8,7 +8,8 @@ relevant source code as appropriate.
`swagger-php` will scan your project and merge all meta-data into one` @OA\OpenApi` annotation.
::: warning
As of `swagger-php` v4 all annotations or attributes must be associated with code (`class`, `method`, `parameter` or `enum`)
As of `swagger-php` v4 all annotations or attributes must be associated with
a structural element (`class`, `method`, `parameter` or `enum`)
:::
## Context awareness

View File

@ -275,7 +275,7 @@ Form posts are `@OA\Post` requests with a `multipart/form-data` `@OA\RequestBody
```
## Default security scheme for all endpoints
Unless specified each endpoint needs to declare what security schemes it supports. However, there is a way to
Unless specified each endpoint needs to declare what security schemes it supports. However, there is a way
to also configure security schemes globally for the whole API.
This is done on the `@OA\OpenApi` annotations:
@ -409,7 +409,7 @@ There are two scenarios where this can happen
2. There are multiple global response declared, again more than one with the same `response` value.
## Callbacks
The API does incllude basic support for callbacks. However, this needs to be set up mostly manually.
The API does include basic support for callbacks. However, this needs to be set up mostly manually.
**Example**
```php
@ -442,7 +442,7 @@ The API does incllude basic support for callbacks. However, this needs to be set
```
## (Mostly) virtual models
Typically a model is annotated by adding a `@OA\Schema` annotation to the class and then individual `@OA\Property` annotations
Typically, a model is annotated by adding a `@OA\Schema` annotation to the class and then individual `@OA\Property` annotations
to the individually declared class properties.
It is possible, however, to nest `O@\Property` annotations inside a schema even without properties. In fact, all that is needed
@ -482,7 +482,7 @@ class Book
This works, but is not very convenient.
First of all, when using custom schema names (`schema: 'user'`), this needs to be taken into account everywhere.
First, when using custom schema names (`schema: 'user'`), this needs to be taken into account everywhere.
Secondly, having to write `ref: '#/components/schemas/user'` is tedious and error-prone.
Using attributes all this changes as we can take advantage of PHP itself by referring to a schema by its (fully qualified)

View File

@ -12,7 +12,7 @@
By default the output format is YAML. If a filename is given (via `--output` or `-o`)
the tool will use the file extension to determine the format.
The `--format` option can be used to force a specifc format.
The `--format` option can be used to force a specific format.
:::
For a list of all available options use the `-h` option

View File

@ -12,7 +12,7 @@ We recommend adding `swagger-php` to your project using [Composer](https://getco
Alternatively, use the composer `global` argument to install `swagger-php` globally.
```ell
```shell
> composer global require zircote/swagger-php
```
::: warning PATH variables

View File

@ -1,6 +1,6 @@
# Migrating to v3
Swagger-PHP 3.x generates a openapi.json file that follows the [OpenAPI Version 3.0.x Specification](https://github.com/OAI/OpenAPI-Specification).
Swagger-PHP 3.x generates an openapi.json file that follows the [OpenAPI Version 3.0.x Specification](https://github.com/OAI/OpenAPI-Specification).
If you need to output the older 2.x specification use OpenApi-php 2.x
@ -12,8 +12,8 @@ Annotations can't be used as string anymore, you'll need to call `toYaml()` or `
## Updated CLI
- Added colors
- No output for succesful execution (Removed summary)
- non-zero exit when an error occured.
- No output for successful execution (Removed summary)
- non-zero exit when an error occurred.
- Defaults to yaml
- Defaults to stdout. To save to openapi.yaml use `-o` or `>`

View File

@ -61,12 +61,12 @@ One of the few differences between annotations and attributes visible in the abo
is not nested within `OA\Info`. Nesting of attributes is possible and required in certain cases however, **in cases where there
is no ambiguity attributes may be all written on the top level** and swagger-php will do the rest.
## Annotations must be associated with code
## Annotations must be associated with a structural element
The (now legacy) way of parsing PHP files meant that docblocks could live in a file without a single line
of actual PHP code.
PHP Attributes cannot exist in isolation; they need code to be associated with and then are available
via reflection on the associated code.
via reflection on the associated structural element.
In order to allow to keep supporting annotations and the code simple it made sense to treat annotations and attributes
the same in this respect.
@ -100,7 +100,7 @@ The attachable annotation is similar to the OpenApi vendor extension `x=`. The m
Their main purpose is to make customizing swagger-php easier by allowing to add arbitrary data to any annotation.
One possible use case could be custom annotations. Classes extnding `Attachable` are allowed to limit
One possible use case could be custom annotations. Classes extending `Attachable` are allowed to limit
the allowed parent annotations. This means it would be easy to create a new attribute to flag certain endpoints
as private and exclude them under certain conditions from the spec (via a custom processor).

View File

@ -11,7 +11,18 @@ The endpoint, in turn, needs to have a path and at least one response.
With the above in mind a minimal API with a single endpoint could look like this
<<< @/snippets/minimal_api.php
<codeblock id="minimal">
<template v-slot:an>
<<< @/snippets/minimal_api_annotations.php
</template>
<template v-slot:at>
<<< @/snippets/minimal_api_attributes.php
</template>
</codeblock>
with the resulting OpenAPI document like this
@ -19,7 +30,7 @@ with the resulting OpenAPI document like this
::: warning Code locations
Attributes and annotations can be added anywhere on declarations in code as defined by the PHP docs.
These are limited to the extend of what the PHP Reflection APIs supports.
These are limited to the extent of what the PHP Reflection APIs supports.
:::
## Optional elements

View File

@ -2,7 +2,7 @@
## Processing flow
- The `Generator` iterates over the given sources (Symfony `Finder`, file/directoy list, etc)
- The `Generator` iterates over the given sources (Symfony `Finder`, file/directory list, etc)
- The configured analyser (`AnalyserInterface`) reads the files and builds an `Analysis` object.
Default (as of v4) is the `ReflectionAnalyser`. Alternatively, there is the `TokenAnalyser` which was the default in v3.
- The `Analysis` object and its annotations are then processed by the configured processors.
@ -24,7 +24,7 @@ Typically, there will be a processor that uses the data to augment/enrich the an
## Analysis
Contains all detected annotations and other relevant meta data.
Contains all detected annotations and other relevant meta-data.
It uses a `SplObjectStorage` instance to store the parsed annotations.
@ -41,7 +41,7 @@ npm install vitepress
### Workflow
* Edit `.md` files in the `docs` folder
* Update annotation / attribute PHP docblocks.<br>These will be extracted during publishing intot the [reference](../reference/) section.
* Update annotation / attribute PHP docblocks.<br>These will be extracted during publishing into the [reference](../reference/) section.
* Run 'composer docs:build' to check for any errors
* Run 'composer docs:dev' to test the generated documentation locally (`localhost:3000`)
* Create PR and update `master`

View File

@ -20,7 +20,20 @@ features:
### 2. Update your code
<<< @/snippets/minimal_api.php
Add `swagger-php` annotations or attributes to your source code.
<codeblock id="minimal">
<template v-slot:an>
<<< @/snippets/minimal_api_annotations.php
</template>
<template v-slot:at>
<<< @/snippets/minimal_api_attributes.php
</template>
</codeblock>
### 3. Generate OpenAPI documentation

View File

@ -8,7 +8,7 @@
"deploy": "npm run build && git-directory-deploy --branch gh-pages --directory .vitepress/dist/"
},
"devDependencies": {
"git-directory-deploy": "^1.5.1",
"vitepress": "^0.21.6"
"vitepress": "^0.22",
"vue3-tabs-component": "^1.0.8"
}
}

View File

@ -167,7 +167,7 @@ The value field and externalValue field are mutually exclusive.<br />
To represent examples of media types that cannot naturally be represented<br />
in JSON or YAML, use a string value to contain the example, escaping where necessary.</p></dd>
<dt><strong>externalValue</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>A URL that points to the literal example.<br />
<dd><p>An URL that points to the literal example.<br />
<br />
This provides the capability to reference examples that cannot easily be included<br />
in JSON or YAML documents.<br />
@ -218,15 +218,15 @@ Configuration details for a supported OAuth Flow.
<dt><strong>authorizationUrl</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The authorization url to be used for this flow.<br />
<br />
This must be in the form of a url.</p></dd>
This must be in the form of an url.</p></dd>
<dt><strong>tokenUrl</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The token URL to be used for this flow.<br />
<br />
This must be in the form of a url.</p></dd>
This must be in the form of an url.</p></dd>
<dt><strong>refreshUrl</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The URL to be used for obtaining refresh tokens.<br />
<br />
This must be in the form of a url.</p></dd>
This must be in the form of an url.</p></dd>
<dt><strong>flow</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>Flow name.<br />
<br />
@ -345,9 +345,9 @@ The metadata may be used by the clients if needed and may be presented in editin
<br />
CommonMark syntax may be used for rich text representation.</p></dd>
<dt><strong>termsOfService</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>A URL to the Terms of Service for the API.<br />
<dd><p>An URL to the Terms of Service for the API.<br />
<br />
Must be in the format of a url.</p></dd>
Must be in the format of an url.</p></dd>
<dt><strong>version</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API implementation version).</p></dd>
</dl>
@ -398,7 +398,7 @@ License information for the exposed API.
<dt><strong>identifier</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>An SPDX license expression for the API. The `identifier` field is mutually exclusive of the `url` field.</p></dd>
<dt><strong>url</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>A URL to the license used for the API. This MUST be in the form of a URL.<br />
<dd><p>An URL to the license used for the API. This MUST be in the form of an URL.<br />
<br />
The `url` field is mutually exclusive of the `identifier` field.</p></dd>
</dl>
@ -581,7 +581,7 @@ A unique parameter is defined by a combination of a name and location.
<dt><strong>parameter</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The key into <code>Components::parameters</code> or <code>PathItem::parameters</code> array.</p></dd>
<dt><strong>name</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The (case sensitive) name of the parameter.<br />
<dd><p>The (case-sensitive) name of the parameter.<br />
<br />
If in is "path", the name field must correspond to the associated path segment from the path field in the Paths Object.<br />
<br />
@ -693,7 +693,7 @@ This option replaces collectionFormat equal to pipes from OpenAPI 2.0.</p></dd>
Describes the operations available on a single path.
A Path Item may be empty, due to ACL constraints.
The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available.
The path itself is still exposed to the documentation viewer, but they will not know which operations and parameters are available.
#### Allowed in
---
@ -1037,7 +1037,7 @@ Bearer tokens are usually generated by an authorization server, so this informat
<dt><strong>scheme</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The name of the HTTP Authorization scheme.</p><p><i>See</i>: <a href="https://tools.ietf.org/html/rfc7235#section-5.1">RFC7235</a></p></dd>
<dt><strong>openIdConnectUrl</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of a URL.</p></dd>
<dd><p>OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of an URL.</p></dd>
</dl>
#### Reference
@ -1060,7 +1060,7 @@ An object representing a server.
---
<dl>
<dt><strong>url</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>A URL to the target host.<br />
<dd><p>An URL to the target host.<br />
<br />
This URL supports Server Variables and may be relative,<br />
to indicate that the host location is relative to the location where the OpenAPI document is being served.<br />
@ -1092,8 +1092,8 @@ An object representing a server variable for server URL template substitution.
<dl>
<dt><strong>serverVariable</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The key into Server->variables array.</p></dd>
<dt><strong>enum</strong> : <span style="font-family: monospace;">string[]</span></dt>
<dd><p>An enumeration of string values to be used if the substitution options are from a limited set.</p></dd>
<dt><strong>enum</strong> : <span style="font-family: monospace;">string[]|int[]|float[]</span></dt>
<dd><p>An enumeration of values to be used if the substitution options are from a limited set.</p></dd>
<dt><strong>default</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The default value to use for substitution, and to send, if an alternate value is not supplied.<br />
<br />
@ -1180,7 +1180,7 @@ and only if wrapped is <code>true</code>.<br />
<br />
If wrapped is <code>false</code>, it will be ignored.</p></dd>
<dt><strong>namespace</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The URL of the namespace definition. Value SHOULD be in the form of a URL.</p></dd>
<dd><p>The URL of the namespace definition. Value SHOULD be in the form of an URL.</p></dd>
<dt><strong>prefix</strong> : <span style="font-family: monospace;">string</span></dt>
<dd><p>The prefix to be used for the name.</p></dd>
<dt><strong>attribute</strong> : <span style="font-family: monospace;">bool</span></dt>

View File

@ -35,9 +35,9 @@ The two configuration options for the underlying Doctrine doc-block parser `alia
are not part of this function and need to be set separately.
Being static this means setting them back is the callers responsibility and there is also the fact that
some of the Doctrine configuration currently can not be reverted easily.
some Doctrine configuration currently can not be reverted easily.
Therefore, having a single side-effect free way of using swwagger-php seemed like a good idea...
Therefore, having a single side effect free way of using swagger-php seemed like a good idea...
## The `\OpenApi\Generator` class
@ -80,7 +80,7 @@ Defaults:
Advantages:
* The `Generator` code will handle configuring things as before in a single place
* Static settings will be reverted to defaults once finished
* Static settings will be reverted to the default once finished
* The get/set methods allow for using type hints
* Static configuration is deprecated and can be removed at some point without code changes
* Build in support for PSR logger

View File

@ -0,0 +1,27 @@
<?php
use OpenApi\Annotations as OA;
/**
* @OA\Info(
* title="My First API",
* version="0.1"
* )
*/
class OpenApi {}
class MyController {
/**
* @OA\Get(
* path="/api/data.json",
* @OA\Response(
* response="200",
* description="The data"
* )
* )
*/
public function getResource() {
// ...
}
}

View File

@ -6,6 +6,7 @@ use OpenApi\Attributes as OA;
class OpenApi {}
class MyController {
#[OA\Get(path: '/api/data.json')]
#[OA\Response(response: '200', description: 'The data')]
public function getResource() {

View File

@ -59,7 +59,7 @@ class Examples extends AbstractAnnotation
public $value = Generator::UNDEFINED;
/**
* A URL that points to the literal example.
* An URL that points to the literal example.
*
* This provides the capability to reference examples that cannot easily be included
* in JSON or YAML documents.

View File

@ -20,7 +20,7 @@ class Flow extends AbstractAnnotation
/**
* The authorization url to be used for this flow.
*
* This must be in the form of a url.
* This must be in the form of an url.
*
* @var string
*/
@ -29,7 +29,7 @@ class Flow extends AbstractAnnotation
/**
* The token URL to be used for this flow.
*
* This must be in the form of a url.
* This must be in the form of an url.
*
* @var string
*/
@ -38,7 +38,7 @@ class Flow extends AbstractAnnotation
/**
* The URL to be used for obtaining refresh tokens.
*
* This must be in the form of a url.
* This must be in the form of an url.
*
* @var string
*/

View File

@ -36,9 +36,9 @@ class Info extends AbstractAnnotation
public $description = Generator::UNDEFINED;
/**
* A URL to the Terms of Service for the API.
* An URL to the Terms of Service for the API.
*
* Must be in the format of a url.
* Must be in the format of an url.
*
* @var string
*/

View File

@ -32,7 +32,7 @@ class License extends AbstractAnnotation
public $identifier = Generator::UNDEFINED;
/**
* A URL to the license used for the API. This MUST be in the form of a URL.
* An URL to the license used for the API. This MUST be in the form of an URL.
*
* The `url` field is mutually exclusive of the `identifier` field.
*

View File

@ -47,7 +47,7 @@ class OpenApi extends AbstractAnnotation
/**
* An array of <code>@OA\Server</code> objects, which provide connectivity information to a target server.
*
* If not provided, or is an empty array, the default value would be a Server Object with a url value of <code>/</code>.
* If not provided, or is an empty array, the default value would be a Server Object with an url value of <code>/</code>.
*
* @var Server[]
*/

View File

@ -118,7 +118,7 @@ abstract class Operation extends AbstractAnnotation
*
* Each value in the map is a Callback Object that describes a request that may be initiated by the API provider
* and the expected responses. The key value used to identify the callback object is an expression, evaluated at
* runtime, that identifies a URL to use for the callback operation.
* runtime, that identifies an URL to use for the callback operation.
*
* @var callable[]
*/

View File

@ -34,7 +34,7 @@ class Parameter extends AbstractAnnotation
public $parameter = Generator::UNDEFINED;
/**
* The (case sensitive) name of the parameter.
* The (case-sensitive) name of the parameter.
*
* If in is "path", the name field must correspond to the associated path segment from the path field in the Paths Object.
*

View File

@ -12,7 +12,7 @@ use OpenApi\Generator;
* Describes the operations available on a single path.
*
* A Path Item may be empty, due to ACL constraints.
* The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available.
* The path itself is still exposed to the documentation viewer, but they will not know which operations and parameters are available.
*
* @see [OAI Path Item Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#path-item-object)
*

View File

@ -83,7 +83,7 @@ class SecurityScheme extends AbstractAnnotation
public $scheme = Generator::UNDEFINED;
/**
* OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of a URL.
* OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of an URL.
*
* @var string
*/

View File

@ -18,7 +18,7 @@ use OpenApi\Generator;
class Server extends AbstractAnnotation
{
/**
* A URL to the target host.
* An URL to the target host.
*
* This URL supports Server Variables and may be relative,
* to indicate that the host location is relative to the location where the OpenAPI document is being served.

View File

@ -29,7 +29,7 @@ class Xml extends AbstractAnnotation
public $name = Generator::UNDEFINED;
/**
* The URL of the namespace definition. Value SHOULD be in the form of a URL.
* The URL of the namespace definition. Value SHOULD be in the form of an URL.
*
* @var string
*/