add new types and info page

This commit is contained in:
Malte Teichert
2024-05-20 01:59:07 +02:00
parent b3138b7a7f
commit 5da492339b
8 changed files with 421 additions and 149 deletions

View File

@@ -1,4 +1,4 @@
<script lang="ts"> <!-- <script lang="ts">
import { openApiStore } from '$lib'; import { openApiStore } from '$lib';
import { import {
apiKeyAuthTemplate, apiKeyAuthTemplate,
@@ -80,4 +80,4 @@
Add Security Schema Add Security Schema
</button> </button>
</span> </span>
</form> </form> -->

View File

@@ -1,13 +1,6 @@
<script lang="ts"> <script lang="ts">
import { popup, type PopupSettings } from '@skeletonlabs/skeleton';
import Info from '../icons/Info.svelte'; import Info from '../icons/Info.svelte';
import { openApiStore } from '$lib'; import { openApiStore } from '$lib';
const descriptionTooltip: PopupSettings = {
event: 'click',
target: 'descriptionTooltip',
placement: 'top'
};
</script> </script>
<form class="container mx-auto card px-6 py-4 space-y-4"> <form class="container mx-auto card px-6 py-4 space-y-4">
@@ -18,20 +11,17 @@
name="title" name="title"
placeholder="Sample API" placeholder="Sample API"
type="text" type="text"
bind:value={$openApiStore.title} bind:value={$openApiStore.info.title}
required
/> />
</label> </label>
<label class="text-xl space-y-2"> <label class="text-xl space-y-2">
<span> <span> Description (optional) </span>
Description (optional) <button type="button" use:popup={descriptionTooltip}>
<Info />
</button>
</span>
<textarea <textarea
class="textarea" class="textarea"
name="description" name="description"
placeholder="Sample API description" placeholder="Optional multiline or single-line description. Supports Markdown."
bind:value={$openApiStore.description} bind:value={$openApiStore.info.description}
/> />
</label> </label>
<label class="text-xl space-y-2"> <label class="text-xl space-y-2">
@@ -41,13 +31,51 @@
name="version" name="version"
placeholder="0.1.0" placeholder="0.1.0"
type="text" type="text"
bind:value={$openApiStore.version} bind:value={$openApiStore.info.version}
required
/> />
</label> </label>
<label class="text-xl space-y-2">
<span>Terms of Service (optional)</span>
<input
class="input"
name="termsOfService"
placeholder="https://example.com/terms"
type="url"
bind:value={$openApiStore.info.termsOfService}
/>
</label>
<div class="border-token rounded-container-token space-y-4 p-4">
<h4 class="h4">Contact Information</h4>
<label class="text-xl space-y-2">
<span>Name (optional)</span>
<input
class="input"
name="contactName"
placeholder="John Doe"
type="text"
bind:value={$openApiStore.info.contact.name}
/>
</label>
<label class="text-xl space-y-2">
<span>Email (optional)</span>
<input
class="input"
name="contactEmail"
placeholder="email@example.com"
type="email"
bind:value={$openApiStore.info.contact.email}
/>
</label>
<label class="text-xl space-y-2">
<span>URL (optional)</span>
<input
class="input"
name="contactUrl"
placeholder="https://example.com"
type="url"
bind:value={$openApiStore.info.contact.url}
/>
</label>
</div>
</form> </form>
<!-- Description Tooltip -->
<div class="card px-4 py-2 variant-filled-primary" data-popup="descriptionTooltip">
<p>Optional multiline or single-line description. Supports Markdown.</p>
<div class="arrow variant-filled-primary" />
</div>

View File

@@ -1,4 +1,4 @@
<script lang="ts"> <!-- <script lang="ts">
import { openApiStore } from '$lib'; import { openApiStore } from '$lib';
import ServerInput from '../atoms/ServerInput.svelte'; import ServerInput from '../atoms/ServerInput.svelte';
@@ -35,10 +35,9 @@
{/if} {/if}
{/each} {/each}
</ul> </ul>
<!-- Add another Server Button -->
<span class="flex justify-center" class:!mt-0={$openApiStore.servers.length === 0}> <span class="flex justify-center" class:!mt-0={$openApiStore.servers.length === 0}>
<button type="button" class="btn variant-filled-primary" on:click={addServer}> <button type="button" class="btn variant-filled-primary" on:click={addServer}>
Add Server Add Server
</button> </button>
</span> </span>
</form> </form> -->

View File

@@ -1,12 +1,40 @@
import type { OpenAPI } from './types';
import { persisted } from 'svelte-persisted-store'; import { persisted } from 'svelte-persisted-store';
import type { OpenAPIV3 } from './openAPITypes';
export const localStoragePrefix = 'openapigen-'; export const localStoragePrefix = 'openapigen-';
export const openApiStore = persisted<OpenAPI>(`${localStoragePrefix}openApi`, { export const openApiStore = persisted<OpenAPIV3.Document>(`${localStoragePrefix}openApi`, {
title: '', openapi: '3.0.0', // OpenAPI version
version: '', info: {
description: '', /** Title of the API (required) */
title: '',
/** Description of the API (optional) */
description: '',
/** Terms of service link (optional) */
termsOfService: '',
/** API Version (required) */
version: '',
/** Contact Information */
contact: {
/** Name of the contact person/organization. */
name: '', // optional
/** URL pointing to the contact information. MUST be in the format of a URL. */
url: '', // optional
/** Email address of the contact person/organization. MUST be in the format of an email address. */
email: '' // optional
},
license: {
name: '', // required if license is included
url: '' // optional
}
},
servers: [], servers: [],
securitySchemas: [] paths: {},
components: {},
security: [],
tags: [],
externalDocs: {
description: '',
url: ''
}
}); });

330
src/lib/openAPITypes.d.ts vendored Normal file
View File

@@ -0,0 +1,330 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
export namespace OpenAPIV3 {
interface Document<T extends {} = {}> {
openapi: string;
info: InfoObject;
servers?: ServerObject[];
paths: PathsObject<T>;
components?: ComponentsObject;
security?: SecurityRequirementObject[];
tags?: TagObject[];
externalDocs?: ExternalDocumentationObject;
'x-express-openapi-additional-middleware'?: (
| ((request: any, response: any, next: any) => Promise<void>)
| ((request: any, response: any, next: any) => void)
)[];
'x-express-openapi-validation-strict'?: boolean;
}
interface InfoObject {
title: string;
description: string;
termsOfService: string;
contact: ContactObject;
license: LicenseObject;
version: string;
}
interface ContactObject {
name?: string;
url?: string;
email?: string;
}
interface LicenseObject {
name: string;
url?: string;
}
interface ServerObject {
url: string;
description?: string;
variables?: {
[variable: string]: ServerVariableObject;
};
}
interface ServerVariableObject {
enum?: string[];
default: string;
description?: string;
}
interface PathsObject<T extends {} = {}, P extends {} = {}> {
[pattern: string]: (PathItemObject<T> & P) | undefined;
}
enum HttpMethods {
GET = 'get',
PUT = 'put',
POST = 'post',
DELETE = 'delete',
OPTIONS = 'options',
HEAD = 'head',
PATCH = 'patch',
TRACE = 'trace'
}
type PathItemObject<T extends {} = {}> = {
$ref?: string;
summary?: string;
description?: string;
servers?: ServerObject[];
parameters?: (ReferenceObject | ParameterObject)[];
} & {
[method in HttpMethods]?: OperationObject<T>;
};
type OperationObject<T extends {} = {}> = {
tags?: string[];
summary?: string;
description?: string;
externalDocs?: ExternalDocumentationObject;
operationId?: string;
parameters?: (ReferenceObject | ParameterObject)[];
requestBody?: ReferenceObject | RequestBodyObject;
responses: ResponsesObject;
callbacks?: {
[callback: string]: ReferenceObject | CallbackObject;
};
deprecated?: boolean;
security?: SecurityRequirementObject[];
servers?: ServerObject[];
} & T;
interface ExternalDocumentationObject {
description?: string;
url: string;
}
interface ParameterObject extends ParameterBaseObject {
name: string;
in: string;
}
interface HeaderObject extends ParameterBaseObject {}
interface ParameterBaseObject {
description?: string;
required?: boolean;
deprecated?: boolean;
allowEmptyValue?: boolean;
style?: string;
explode?: boolean;
allowReserved?: boolean;
schema?: ReferenceObject | SchemaObject;
example?: any;
examples?: {
[media: string]: ReferenceObject | ExampleObject;
};
content?: {
[media: string]: MediaTypeObject;
};
}
type NonArraySchemaObjectType = 'boolean' | 'object' | 'number' | 'string' | 'integer';
type ArraySchemaObjectType = 'array';
type SchemaObject = ArraySchemaObject | NonArraySchemaObject;
interface ArraySchemaObject extends BaseSchemaObject {
type: ArraySchemaObjectType;
items: ReferenceObject | SchemaObject;
}
interface NonArraySchemaObject extends BaseSchemaObject {
type?: NonArraySchemaObjectType;
}
interface BaseSchemaObject {
title?: string;
description?: string;
format?: string;
default?: any;
multipleOf?: number;
maximum?: number;
exclusiveMaximum?: boolean;
minimum?: number;
exclusiveMinimum?: boolean;
maxLength?: number;
minLength?: number;
pattern?: string;
additionalProperties?: boolean | ReferenceObject | SchemaObject;
maxItems?: number;
minItems?: number;
uniqueItems?: boolean;
maxProperties?: number;
minProperties?: number;
required?: string[];
enum?: any[];
properties?: {
[name: string]: ReferenceObject | SchemaObject;
};
allOf?: (ReferenceObject | SchemaObject)[];
oneOf?: (ReferenceObject | SchemaObject)[];
anyOf?: (ReferenceObject | SchemaObject)[];
not?: ReferenceObject | SchemaObject;
nullable?: boolean;
discriminator?: DiscriminatorObject;
readOnly?: boolean;
writeOnly?: boolean;
xml?: XMLObject;
externalDocs?: ExternalDocumentationObject;
example?: any;
deprecated?: boolean;
}
interface DiscriminatorObject {
propertyName: string;
mapping?: {
[value: string]: string;
};
}
interface XMLObject {
name?: string;
namespace?: string;
prefix?: string;
attribute?: boolean;
wrapped?: boolean;
}
interface ReferenceObject {
$ref: string;
}
interface ExampleObject {
summary?: string;
description?: string;
value?: any;
externalValue?: string;
}
interface MediaTypeObject {
schema?: ReferenceObject | SchemaObject;
example?: any;
examples?: {
[media: string]: ReferenceObject | ExampleObject;
};
encoding?: {
[media: string]: EncodingObject;
};
}
interface EncodingObject {
contentType?: string;
headers?: {
[header: string]: ReferenceObject | HeaderObject;
};
style?: string;
explode?: boolean;
allowReserved?: boolean;
}
interface RequestBodyObject {
description?: string;
content: {
[media: string]: MediaTypeObject;
};
required?: boolean;
}
interface ResponsesObject {
[code: string]: ReferenceObject | ResponseObject;
}
interface ResponseObject {
description: string;
headers?: {
[header: string]: ReferenceObject | HeaderObject;
};
content?: {
[media: string]: MediaTypeObject;
};
links?: {
[link: string]: ReferenceObject | LinkObject;
};
}
interface LinkObject {
operationRef?: string;
operationId?: string;
parameters?: {
[parameter: string]: any;
};
requestBody?: any;
description?: string;
server?: ServerObject;
}
interface CallbackObject {
[url: string]: PathItemObject;
}
interface SecurityRequirementObject {
[name: string]: string[];
}
interface ComponentsObject {
schemas?: {
[key: string]: ReferenceObject | SchemaObject;
};
responses?: {
[key: string]: ReferenceObject | ResponseObject;
};
parameters?: {
[key: string]: ReferenceObject | ParameterObject;
};
examples?: {
[key: string]: ReferenceObject | ExampleObject;
};
requestBodies?: {
[key: string]: ReferenceObject | RequestBodyObject;
};
headers?: {
[key: string]: ReferenceObject | HeaderObject;
};
securitySchemes?: {
[key: string]: ReferenceObject | SecuritySchemeObject;
};
links?: {
[key: string]: ReferenceObject | LinkObject;
};
callbacks?: {
[key: string]: ReferenceObject | CallbackObject;
};
}
type SecuritySchemeObject =
| HttpSecurityScheme
| ApiKeySecurityScheme
| OAuth2SecurityScheme
| OpenIdSecurityScheme;
interface HttpSecurityScheme {
type: 'http';
description?: string;
scheme: string;
bearerFormat?: string;
}
interface ApiKeySecurityScheme {
type: 'apiKey';
description?: string;
name: string;
in: string;
}
interface OAuth2SecurityScheme {
type: 'oauth2';
description?: string;
flows: {
implicit?: {
authorizationUrl: string;
refreshUrl?: string;
scopes: {
[scope: string]: string;
};
};
password?: {
tokenUrl: string;
refreshUrl?: string;
scopes: {
[scope: string]: string;
};
};
clientCredentials?: {
tokenUrl: string;
refreshUrl?: string;
scopes: {
[scope: string]: string;
};
};
authorizationCode?: {
authorizationUrl: string;
tokenUrl: string;
refreshUrl?: string;
scopes: {
[scope: string]: string;
};
};
};
}
interface OpenIdSecurityScheme {
type: 'openIdConnect';
description?: string;
openIdConnectUrl: string;
}
interface TagObject {
name: string;
description?: string;
externalDocs?: ExternalDocumentationObject;
}
}

View File

@@ -1,81 +0,0 @@
// Basic Auth
export interface BasicAuth extends Auth {
type: 'http';
scheme: 'basic';
}
// Bearer Token
export interface BearerAuth extends Auth {
type: 'http';
scheme: 'bearer';
bearerFormat?: string; // arbitrary value for documentation purposes
}
// API Key
export interface ApiKeyAuth extends Auth {
type: 'apiKey';
in: 'header' | 'query' | 'cookie';
name: string;
}
// OAuth2
export interface OAuth2Auth extends Auth {
type: 'oauth2';
description: string;
flows: Flows[];
}
type Scope = [
{
scope: string;
description?: string;
}
];
export type Flows =
| OAuth2AuchorizationCodeFlow
| OAuth2ImplicitFlow
| OAuth2PasswordFlow
| OAuth2ClientCredentialsFlow;
interface OAuth2AuchorizationCodeFlow {
name: 'authorizationCode';
authorizationUrl: string;
tokenUrl: string;
scopes: Scope[];
}
interface OAuth2ImplicitFlow {
name: 'implicit';
authorizationUrl: string;
scopes: Scope[];
}
interface OAuth2PasswordFlow {
name: 'password';
tokenUrl: string;
scopes: Scope[];
}
interface OAuth2ClientCredentialsFlow {
name: 'clientCredentials';
tokenUrl: string;
scopes: Scope[];
}
// OpenID Connect
export interface OpenIdConnectAuth extends Auth {
type: 'openIdConnect';
openIdConnectUrl: string;
}
// Cookie Auth
export interface CookieAuth extends Auth {
type: 'apiKey';
in: 'cookie';
name: string;
}
interface Auth {
identifier: string; // a unique name for the auth-configuration
}

View File

@@ -1,32 +0,0 @@
import type {
ApiKeyAuth,
BasicAuth,
BearerAuth,
CookieAuth,
OAuth2Auth,
OpenIdConnectAuth
} from './auth';
export interface OpenAPI extends Info {
servers: Server[];
securitySchemas: SecuritySchema[];
}
export interface Info {
title: string;
version: string;
description?: string;
}
export interface Server {
url: string;
description?: string;
}
export type SecuritySchema =
| BasicAuth
| BearerAuth
| ApiKeyAuth
| OAuth2Auth
| OpenIdConnectAuth
| CookieAuth;

View File

@@ -27,11 +27,11 @@
</Tab> </Tab>
<svelte:fragment slot="panel"> <svelte:fragment slot="panel">
{#if $tabSet === 0} {#if $tabSet === 0}
<Info></Info> <Info />
{:else if $tabSet === 1} {:else if $tabSet === 1}
<Authentication /> <!-- <Authentication /> -->
{:else if $tabSet === 2} {:else if $tabSet === 2}
<Servers /> <!-- <Servers /> -->
{:else if $tabSet === 3} {:else if $tabSet === 3}
<p>Paths</p> <p>Paths</p>
{:else if $tabSet === 4} {:else if $tabSet === 4}