add first version of tailwind docs

This commit is contained in:
Pascal Fischer
2023-05-03 19:00:56 +02:00
parent 9d42e075f7
commit 86b1890396
189 changed files with 26622 additions and 0 deletions

5333
generator/api-back.mdx Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
# Swagger Codegen Ignore
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@@ -0,0 +1 @@
3.0.42

View File

4425
generator/api.mdx Normal file

File diff suppressed because it is too large Load Diff

200
generator/api.ts Normal file
View File

@@ -0,0 +1,200 @@
import template from './templates/ApiTemplate'
import { slugify, toArrayWithKey, toTitle, writeToDisk } from './helpers'
import { OpenAPIV3, OpenAPIV2 } from 'openapi-types'
import * as yaml from 'yaml';
import * as fs from 'fs'
import * as ejs from 'ejs'
export default async function gen(inputFileName: string, outputDir: string, apiUrl: string) {
const specRaw = fs.readFileSync(inputFileName, 'utf8')
const spec = yaml.parse(specRaw) as any
// console.log('spec', spec)
switch (spec.openapi || spec.swagger) {
case '3.0.0':
case '3.0.1':
case '3.0.3':
await gen_v3(spec, outputDir, { apiUrl })
break
default:
console.log('Unrecognized specification version:', spec.openapi)
break
}
}
/**
* Versioned Generator
*/
// OPENAPI-SPEC-VERSION: 3.0.0
type v3OperationWithPath = OpenAPIV3.OperationObject & {
path: string
}
export type enrichedOperation = OpenAPIV3.OperationObject & {
path: string
fullPath: string
operationId: string
}
export type schemaParameter = {
name: string
type: string
description: string
required: boolean
minimum?: number
maximum?: number
minLength?: number
maxLength?: number
enum?: string[]
}
export type schemaObject = {
examples: Object
parameters: schemaParameter[]
}
async function gen_v3(spec: OpenAPIV3.Document, dest: string, { apiUrl }: { apiUrl: string }) {
const specLayout = spec.tags || []
// const operations: enrichedOperation[] = []
const tagGroups = new Map<string, enrichedOperation[]>()
Object.entries(spec.paths).forEach(([key, val]) => {
const fullPath = `${apiUrl}${key}`
toArrayWithKey(val!, 'operation').forEach((o) => {
const operation = o as v3OperationWithPath
const enriched = {
...operation,
path: key,
fullPath,
operationId: slugify(operation.summary!),
responseList: toArrayWithKey(operation.responses!, 'responseCode') || [],
}
let tag = operation.tags.pop()
let tagOperations = tagGroups.get(tag) ?? []
tagGroups.set(tag, tagOperations.concat(enriched))
})
})
let schemas = new Map<string, schemaObject>();
Object.entries(spec.components?.schemas).forEach(([key, val]) => {
const schema = val as OpenAPIV3.SchemaObject
let examples = new Map<string, any>();
let parameters : schemaParameter[] = []
if(schema.allOf){
schema.allOf.forEach((item) => {
if((item as OpenAPIV3.ReferenceObject).$ref){
let schemaObject = schemas.get((item as OpenAPIV3.ReferenceObject).$ref.split('/').pop())
let examplesMap = new Map(Object.entries(schemaObject.examples))
examplesMap.forEach((value, key) => {
examples.set(key, value)
})
parameters = parameters.concat(schemaObject.parameters)
}
if((item as OpenAPIV3.SchemaObject).properties){
Object.entries((item as OpenAPIV3.SchemaObject).properties).forEach(([key, val]) => {
let property = val as OpenAPIV3.SchemaObject
let type
if (property.type === "array") {
type = new Array(resolveType(property.items, spec.components?.schemas))
} else {
type = resolveType(property, spec.components?.schemas)
}
examples.set(key, type)
let parameter: schemaParameter = {
name: key,
type: property.type === "array" ? ((property.items as OpenAPIV3.SchemaObject).type || (property.items as OpenAPIV3.ReferenceObject).$ref.split('/').pop()) + "[]" : property.type,
description: property.description,
required: schema.required?.includes(key) || false,
minimum: property.minimum,
maximum: property.maximum,
minLength: property.minLength,
maxLength: property.maxLength,
enum: property.enum
}
parameters.push(parameter)
})
}
})
} else {
Object.entries(schema.properties).forEach(([key, val]) => {
let property = val as OpenAPIV3.SchemaObject
let type
if(property.type === "array"){
type = new Array(resolveType(property.items, spec.components?.schemas))
} else {
type = resolveType(property, spec.components?.schemas)
}
examples.set(key, type)
let parameter : schemaParameter = {
name: key,
type: property.type === "array" ? ((property.items as OpenAPIV3.SchemaObject).type || (property.items as OpenAPIV3.ReferenceObject).$ref.split('/').pop()) + "[]" : property.type,
description: property.description,
required: schema.required?.includes(key) || false,
minimum: property.minimum,
maximum: property.maximum,
minLength: property.minLength,
maxLength: property.maxLength,
enum: property.enum
}
parameters.push(parameter)
})
}
let output : schemaObject = {
examples: Object.fromEntries(examples),
parameters: parameters
}
schemas.set(key, output)
})
tagGroups.forEach((value: enrichedOperation[], key: string) => {
const operations = value
const sections = specLayout.map((section) => {
return {
...section,
title: toTitle(section.name),
id: slugify(section.name),
operations: operations,
}
})
const content = ejs.render(template, {
info: spec.info,
sections,
operations,
schemas,
})
// Write to disk
let outputFile = dest + "/" + key.toLowerCase().replace(" ", "-") + ".mdx"
writeToDisk(outputFile, content)
// console.log('Saved: ', outputFile)
})
}
function resolveType(items: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | OpenAPIV3.NonArraySchemaObjectType, schemas) : any {
if((items as OpenAPIV3.ReferenceObject).$ref){
let ref = (items as OpenAPIV3.ReferenceObject).$ref
let map = new Map<string, any>()
Object.entries(schemas[ref.split('/').pop()].properties).forEach(([key, val]) => {
let property = val as OpenAPIV3.SchemaObject
let type
if(property.type === "array"){
type = new Array(resolveType(property.items, schemas))
} else {
type = resolveType(property, schemas)
}
map.set(key, type)
})
return Object.fromEntries(map)
}
return (items as OpenAPIV3.ArraySchemaObject).type
}

42
generator/helpers.ts Normal file
View File

@@ -0,0 +1,42 @@
import * as _ from 'lodash'
import * as fs from 'fs'
export const slugify = (text: string) => {
if (!text) return ''
return text
.toString()
.toLowerCase()
.replace(/[. )(]/g, '-') // Replace spaces and brackets -
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
.replace(/\-\-+/g, '-') // Replace multiple - with single -
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, '') // Trim - from end of text
}
// Uppercase the first letter of a string
export const toTitle = (text: string) => {
return text.charAt(0).toUpperCase() + text.slice(1)
}
/**
* writeToDisk()
*/
export const writeToDisk = (fileName: string, content: any) => {
return new Promise((resolve, reject) => {
fs.writeFile(fileName, content, (err: any) => {
if (err) return reject(err)
else return resolve(true)
})
})
}
/**
* Convert Object to Array of values
*/
export const toArrayWithKey = (obj: object, keyAs: string) =>
_.values(
_.mapValues(obj, (value: any, key: string) => {
value[keyAs] = key
return value
})
)

45
generator/index.ts Normal file
View File

@@ -0,0 +1,45 @@
import ApiGenerator from './api'
const main = (command: string[], options: any) => {
handleInput(command[0], options)
}
// Run everything
const argv = require('minimist')(process.argv.slice(2))
main(argv['_'], argv)
function handleInput(command: string, options: any) {
switch (command) {
case 'gen':
DocGenerator(options)
break
default:
console.log('Unrecognized command:', command)
break
}
}
export default async function DocGenerator({
input,
output,
type,
url,
}: {
input: string
output: string
type: 'api'
url?: string
}) {
switch (type) {
case 'api':
await ApiGenerator(input, output, url || '')
break
default:
await console.log('Unrecognized type: ', type)
break
}
return 'Done'
}

3153
generator/openapi.json Normal file

File diff suppressed because it is too large Load Diff

2105
generator/openapi.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,123 @@
const template = `
---
<% operations.forEach(function(operation){ %>
## <%- operation.summary %> {{ tag: '<%- operation.operation.toUpperCase() %>' , label: '<%- operation.path %>' }}
<Row>
<Col>
<%- operation.description %>
<% if(operation.parameters && operation.parameters.filter((parameter) => parameter.in === 'path').length > 0){ %>
#### Path Parameters
<Properties>
<% operation.parameters.filter((parameter) => parameter.in === 'path').forEach(function(parameter){ %>
<Property name="<%- parameter.name %>" type="string" required=\{true\}>
<%- parameter.description %>
</Property>
<% }); -%>
</Properties>
<% }; -%>
<% if(operation.parameters && operation.parameters.filter((parameter) => parameter.in === 'query').length > 0){ %>
#### Query Parameters
<Properties>
<% operation.parameters.filter((parameter) => parameter.in === 'query').forEach(function(parameter){ %>
<Property name="<%- parameter.name %>" type="<%- parameter.schema.type %>" required=\{false\}>
<%- parameter.description %>
</Property>
<% }); -%>
</Properties>
<% }; -%>
<% if(operation.requestBody?.content && operation.requestBody?.content['application/json']){ %>
#### Request-Body Parameters
<Properties>
<% schemas.get(operation.requestBody?.content['application/json'].schema.$ref.split('/').pop())?.parameters.forEach(function(parameter){ %>
<Property name="<%- parameter.name %>" type="<%- parameter.type %>" required=\{<%- parameter.required %>\}
<% if(parameter.enum){ %>
enumList="<%- parameter.enum %>"
<% }; -%>
<% if(parameter.minimum){ %>
min=\{<%- parameter.minimum %>\}
<% }; -%>
<% if(parameter.maximum){ %>
max=\{<%- parameter.maximum %>\}
<% }; -%>
<% if(parameter.minLength){ %>
minLen=\{<%- parameter.minLength %>\}
<% }; -%>
<% if(parameter.maxLength){ %>
maxLen=\{<%- parameter.maxLength %>\}
<% }; -%> >
<%- parameter.description %>
</Property>
<% }); -%>
</Properties>
<% }; -%>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="<%- operation.operation.toUpperCase() %>" label="<%- operation.path %>">
\`\`\`bash {{ title: 'cURL' }}
curl -X <%- operation.operation.toUpperCase() %> <%- operation.fullPath %> \\
-H "Authorization: Bearer {token}" \\
<% if(operation.responseList[0].content && operation.responseList[0].content['application/json']){ -%>
-H 'Accept: application/json' \\<% }; %>
<% if(operation.requestBody?.content && operation.requestBody?.content['application/json']){ -%>
-H 'Content-Type: application/json' \\
--data-raw '<%- JSON.stringify(schemas.get(operation.requestBody?.content['application/json'].schema.$ref?.split('/').pop())?.examples, null, 2) %>'<% }; %>
\`\`\`
\`\`\`js
import ApiClient from '@example/protocol-api'
const client = new ApiClient(token)
await client.contacts.update('WAz8eIbvDR60rouK', {
display_name: 'UncleFrank',
})
\`\`\`
\`\`\`python
from protocol_api import ApiClient
client = ApiClient(token)
client.contacts.update("WAz8eIbvDR60rouK", display_name="UncleFrank")
\`\`\`
\`\`\`php
$client = new \\Protocol\\ApiClient($token);
$client->contacts->update('WAz8eIbvDR60rouK', [
'display_name' => 'UncleFrank',
]);
\`\`\`
</CodeGroup>
<% operation.responseList.forEach(function(response){ %>
<% if(response?.content && response?.content['application/json']){ %>
<% if(response?.content['application/json'].schema.type === 'array'){ %>
<CodeGroup title="Response">
\`\`\`json {{ title: '200' }}
<%- JSON.stringify(new Array(schemas.get(response?.content['application/json'].schema.items.$ref?.split('/').pop())?.examples), null, 2) %>
\`\`\`
</CodeGroup>
<% } else { %>
<CodeGroup title="Response">
\`\`\`json {{ title: '200' }}
<%- JSON.stringify(schemas.get(response?.content['application/json'].schema.$ref?.split('/').pop())?.examples, null, 2) %>
\`\`\`
</CodeGroup>
<% }; -%>
<% }; -%>
<% }); -%>
</Col>
</Row>
---
<% }); -%>
`.trim()
export default template

View File

@@ -0,0 +1,144 @@
const template = `
---
id: usage
slug: /usage
title: Usage
toc_max_heading_level: 3
---
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
<%- info.description %>
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
<% sections.forEach(function(section){ %>
## <%- section.title %> [#<%= section.id %>]
<%- section.description %>
<% section.operations.forEach(function(operation){ %>
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
### <%- operation.summary %> [#<%- operation.operationId %>]
\`\`\`
<%- operation.operation.toUpperCase() %> <%- operation.fullPath %>
\`\`\`
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
<% if(operation.parameters && operation.parameters.filter((parameter) => parameter.in === 'path').length > 0){ %>
#### Path Parameters
<ul className="method-list-group not-prose">
<% operation.parameters
.filter((parameter) => parameter.in === 'path').forEach(function(parameter){ %>
<li className="method-list-item">
<h4 className="method-list-item-label">
<span className="method-list-item-label-name">
<%- parameter.name %>
</span>
<span className="method-list-item-label-badge">
<%- parameter.required ? 'required' : 'optional' %>
</span>
<span className="method-list-item-validation">
<%- parameter.type %>
</span>
</h4>
<% if(parameter.example){ %>
<h4 className="method-list-item-label">
Example:
<span className="method-list-item-label-badge">
<%- parameter.example %>
</span>
</h4>
<% } %>
<div class="method-list-item-description">
<%- parameter.description %>
</div>
</li>
<% }); %>
</ul>
<% }; %>
<% if(operation.parameters && operation.parameters.filter((parameter) => parameter.in === 'header').length > 0){ %>
#### Header Parameters
<ul className="method-list-group not-prose">
<% operation.parameters
.filter((parameter) => parameter.in === 'header').forEach(function(parameter){ %>
<li className="method-list-item">
<h4 className="method-list-item-label">
<span className="method-list-item-label-name">
<%- parameter.name %>
</span>
<span className="method-list-item-label-badge">
<%- parameter.required ? 'required' : 'optional' %>
</span>
<span className="method-list-item-validation">
<%- parameter.type %>
</span>
</h4>
<% if(parameter.example){ %>
<h4 className="method-list-item-label">
Example:
<span className="method-list-item-label-badge">
<%- parameter.example %>
</span>
</h4>
<% } %>
<div class="method-list-item-description">
<%- parameter.description %>
</div>
</li>
<% }); %>
</ul>
<% }; %>
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
<% if(operation.requestBody?.content && operation.requestBody?.content['application/json']){ %>
#### Body Parameters
\`\`\`json
<%- JSON.stringify(operation.requestBody?.content['application/json'], null, 2) %>
\`\`\`
<% }; %>
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
#### Responses
<Tabs scrollable size="small" type="underlined" defaultActiveId="<%- operation.responseList[0].responseCode %>">
<% operation.responseList.forEach(function(response){ %>
<TabPanel id="<%- response.responseCode %>" label="<%- response.responseCode %>">
<%- response.description %>
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
<% if(response?.content && response?.content['application/json']){ %>
\`\`\`json
<%- JSON.stringify(response.content['application/json'], null, 2) %>
\`\`\`
<% }; %>
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
</TabPanel>
<% }); %>
</Tabs>
<br />
<% }); %>
<% }); %>
`.trim()
export default template

13
generator/tsconfig.json Normal file
View File

@@ -0,0 +1,13 @@
// generator files need their own tsconfig.json because they don't like "module": "esnext" setting that nextjs requires in the main tsconfig
{
"compilerOptions": {
"incremental": true,
"noImplicitAny": false,
"baseUrl": ".",
"paths": {
"~/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,34 @@
import { SpecLink } from './Spec'
import { Url } from 'url'
export type CliInfo = {
id: string
version: string
title: string
language: string
source: Url
bugs: Url
spec: Url
description: string
options: string
}
export type CliCommand = {
id: string
title: string
summary: string
description: string
tags: string[]
links: SpecLink[]
usage: string
subcommands: string[]
options: string
}
export interface CliSpec {
clispec: '001'
info: CliInfo
commands: CliCommand[]
}

View File

@@ -0,0 +1,36 @@
import { SpecLink } from './Spec'
import { Url } from 'url'
export type Tag = {
id: string
title: string
description?: string
}
export type ConfigInfo = {
id: string
version: string
title: string
source: Url
bugs: Url
spec: Url
description: string
tags: Tag[]
}
export type ConfigParameter = {
id: string
title: string
tags: string[]
required: boolean
description: string
links: SpecLink[]
}
export interface ConfigSpec {
configspec: '001'
info: ConfigInfo
parameters: ConfigParameter[]
}

View File

@@ -0,0 +1,75 @@
import { SpecLink } from './Spec'
import { Url } from 'url'
export type SdkInfo = {
id: string
version: string
title: string
language: string
source: Url
bugs: Url
spec: Url
description: string
options: string
}
export type SdkType = {
id: string
title: string
summary: string
source: Url
value: string
ref?: SdkType
links: SpecLink[]
}
export type FunctionAttribute = {
id: string
title: string
required: boolean
description: string
type?: string[]
ref?: string // If a "type" is not supplied, a "ref" must be. This is a pointer to a type.
children: FunctionAttribute[]
}
export type FunctionReturn = {
id: string
title: string
value: string
description: string
ref?: string // This is a pointer to a type.
}
export type FunctionExample = {
id: string
title: string
description?: string
links: SpecLink[]
code: string
returns?: FunctionReturn
}
export type Function = {
id: string
title: string
summary: string
source: Url
description?: string
usage: string
tags: string[]
links: SpecLink[]
attributes?: FunctionAttribute[]
returns?: FunctionReturn[]
examples?: FunctionExample[]
}
export interface SdkSpec {
sdkspec: '001'
info: SdkInfo
functions: Function[]
types: SdkType[]
}

6
generator/types/Spec.ts Normal file
View File

@@ -0,0 +1,6 @@
import { Url } from 'url'
export type SpecLink = {
name: string
url: Url
}