mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-21 09:03:02 +00:00
feat: replace route markdown with openapi
This commit is contained in:
188
src/routes.ts
188
src/routes.ts
@@ -14,10 +14,11 @@
|
||||
*/
|
||||
import {asyncPool} from '@krlwlfrt/async-pool/lib/async-pool';
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {OpenAPIV3} from 'openapi-types';
|
||||
import {basename, dirname, join} from 'path';
|
||||
import {ProjectReflection} from 'typedoc';
|
||||
import {Type} from 'typedoc/dist/lib/models';
|
||||
import {NodesWithMetaInformation, NodeWithMetaInformation, RouteWithMetaInformation} from './common';
|
||||
import {capitalize, NodeWithMetaInformation, RouteWithMetaInformation} from './common';
|
||||
|
||||
/**
|
||||
* Gather relevant information of routes
|
||||
@@ -55,6 +56,19 @@ export async function gatherRouteInformation(reflection: ProjectReflection): Pro
|
||||
|
||||
const route = new importedModule[node.name]();
|
||||
|
||||
// tslint:disable-next-line: no-any
|
||||
const errors = route.errorNames.map((error: any) => {
|
||||
const scError = new importedModule[error.name]();
|
||||
scError.name = error.name;
|
||||
|
||||
return scError;
|
||||
});
|
||||
|
||||
route.responseBodyDescription = module.children!.find(element => element.name === route.responseBodyName)?.comment?.shortText;
|
||||
route.requestBodyDescription = module.children!.find(element => element.name === route.requestBodyName)?.comment?.shortText;
|
||||
|
||||
route.errors = errors;
|
||||
|
||||
routes.push({description: node.comment!, name: node.name, route});
|
||||
}
|
||||
}
|
||||
@@ -69,28 +83,6 @@ export async function gatherRouteInformation(reflection: ProjectReflection): Pro
|
||||
return routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a linked name for a node
|
||||
*
|
||||
* @param name Name of the node
|
||||
* @param node Node itself
|
||||
* @param humanize Whether to humanize the name or not
|
||||
*/
|
||||
export function getLinkedNameForNode(name: string, node: NodeWithMetaInformation, humanize = false): string {
|
||||
const humanizeString = require('humanize-string');
|
||||
|
||||
let printableName = name;
|
||||
|
||||
if (humanize) {
|
||||
printableName = humanizeString(name.substr('SC'.length));
|
||||
}
|
||||
|
||||
let link = `[${printableName}]`;
|
||||
link += `(${getLinkForNode(name, node)})`;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get link for a node
|
||||
*
|
||||
@@ -128,89 +120,85 @@ export function getLinkForNode(name: string, node: NodeWithMetaInformation): str
|
||||
* Generate documentation snippet for one route
|
||||
*
|
||||
* @param routeWithInfo A route instance with its meta information
|
||||
* @param nodes Nodes with meta information
|
||||
* @param outDirSchemasPath Path to directory that will contain relevant schemas for the route
|
||||
* @param schemasToCopy Schemas identified as relevant for this route
|
||||
* @param tagsToKeep Tags / keywords that can be used for grouping routes
|
||||
*/
|
||||
export function generateDocumentationForRoute(routeWithInfo: RouteWithMetaInformation,
|
||||
nodes: NodesWithMetaInformation): string {
|
||||
let output = '';
|
||||
|
||||
export function generateOpenAPIForRoute(routeWithInfo: RouteWithMetaInformation,
|
||||
outDirSchemasPath: string,
|
||||
schemasToCopy: string[],
|
||||
tagsToKeep: string[]): OpenAPIV3.PathItemObject {
|
||||
const route = routeWithInfo.route;
|
||||
const path: OpenAPIV3.PathItemObject = {};
|
||||
|
||||
output += `## \`${route.method} ${route.urlFragment}\``;
|
||||
output += ` ${getLinkedNameForNode(routeWithInfo.name, nodes[routeWithInfo.name], true)}\n\n`;
|
||||
schemasToCopy.push(route.requestBodyName, route.responseBodyName);
|
||||
|
||||
if (typeof routeWithInfo.description.shortText === 'string') {
|
||||
output += `**${routeWithInfo.description.shortText}**\n\n`;
|
||||
}
|
||||
path[(route.method.toLowerCase() as OpenAPIV3.HttpMethods)] = {
|
||||
summary: capitalize(routeWithInfo.description.shortText?.replace(/(Route to |Route for )/gmi, '')),
|
||||
description: routeWithInfo.description.text,
|
||||
requestBody: {
|
||||
description: route.responseBodyDescription ?? undefined,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
$ref: join(outDirSchemasPath, `${route.requestBodyName}.json`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
parameters: [{
|
||||
name: 'X-StApps-Version',
|
||||
in: 'header',
|
||||
schema: {
|
||||
type: 'string',
|
||||
example: '2.0.0',
|
||||
},
|
||||
required: true,
|
||||
}],
|
||||
responses: {},
|
||||
tags: routeWithInfo.tags?.filter(value => tagsToKeep.includes(value)),
|
||||
};
|
||||
|
||||
if (typeof routeWithInfo.description.text === 'string') {
|
||||
output += `${routeWithInfo.description.text.replace('\n', '<br>')}\n\n`;
|
||||
}
|
||||
path[(route.method.toLowerCase() as OpenAPIV3.HttpMethods)]!.responses![route.statusCodeSuccess] = {
|
||||
description: route.responseBodyDescription,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
$ref: join(outDirSchemasPath, `${route.responseBodyName}.json`),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
output += `### Definition
|
||||
|
||||
| parameter | value |
|
||||
| --- | --- |
|
||||
| request | ${getLinkedNameForNode(route.requestBodyName, nodes[route.requestBodyName])} |
|
||||
| response | ${getLinkedNameForNode(route.responseBodyName, nodes[route.responseBodyName])} |
|
||||
| success code | ${route.statusCodeSuccess} |
|
||||
| errors | ${route.errorNames
|
||||
.map((error) => {
|
||||
return getLinkedNameForNode(error.name, nodes[error.name]);
|
||||
})
|
||||
.join('<br>')} |
|
||||
`;
|
||||
if (typeof route.obligatoryParameters === 'object' && Object.keys(route.obligatoryParameters).length > 0) {
|
||||
let parameterTable = '<table><tr><th>parameter</th><th>type</th></tr>';
|
||||
|
||||
for (const parameter in route.obligatoryParameters) {
|
||||
if (!route.obligatoryParameters.hasOwnProperty(parameter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let type = route.obligatoryParameters![parameter];
|
||||
|
||||
if (typeof nodes[type] !== 'undefined') {
|
||||
type = getLinkedNameForNode(type, nodes[type]);
|
||||
}
|
||||
|
||||
parameterTable += `<tr><td>${parameter}</td><td>${type}</td></tr>`;
|
||||
}
|
||||
|
||||
parameterTable += '</table>';
|
||||
|
||||
output += `| obligatory parameters | ${parameterTable} |`;
|
||||
}
|
||||
output += '\n\n';
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map of nodes with their meta information
|
||||
*
|
||||
* @param projectReflection Reflection to get information from
|
||||
*/
|
||||
export function getNodeMetaInformationMap(projectReflection: ProjectReflection): NodesWithMetaInformation {
|
||||
const nodes: NodesWithMetaInformation = {};
|
||||
|
||||
if (typeof projectReflection.children === 'undefined') {
|
||||
throw new Error('Project reflection doesn\'t contain any modules.');
|
||||
}
|
||||
|
||||
// iterate over modules
|
||||
projectReflection.children.forEach((module) => {
|
||||
if (Array.isArray(module.children) && module.children.length > 0) {
|
||||
// iterate over types
|
||||
module.children.forEach((node) => {
|
||||
// add node with module and type
|
||||
nodes[node.name] = {
|
||||
module: module.name.substring(1, module.name.length - 1),
|
||||
type: node.kindString!,
|
||||
};
|
||||
});
|
||||
}
|
||||
route.errors.forEach(error => {
|
||||
schemasToCopy.push(error.name);
|
||||
path[(route.method.toLowerCase() as OpenAPIV3.HttpMethods)]!.responses![error.statusCode] = {
|
||||
description: error.message ?? capitalize(error.name.replace(/([A-Z][a-z])/g,' $1')
|
||||
.replace('SC ', '')),
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
$ref: join(outDirSchemasPath, `${error.name}.json`),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return nodes;
|
||||
if (typeof route.obligatoryParameters === 'object') {
|
||||
for (const [parameter, schemaDefinition] of Object.entries(route.obligatoryParameters)) {
|
||||
const openapiParam: OpenAPIV3.ParameterObject = {
|
||||
in: 'path',
|
||||
name: parameter,
|
||||
required: true,
|
||||
schema: {
|
||||
// TODO make this less of a hack and search copied schemas for the first occurring definition
|
||||
$ref: `schemas/SCSearchResponse.json#/definitions/${schemaDefinition}`,
|
||||
},
|
||||
};
|
||||
path[(route.method.toLowerCase() as OpenAPIV3.HttpMethods)]?.parameters?.push(openapiParam);
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user