Files
openstapps/packages/openapi-generator/src/generator/openapi.js

90 lines
2.6 KiB
JavaScript

/**
* Creates sentence cased string
* @param string {string | undefined}
* @returns {string}
*/
export function capitalize(string) {
return `${string?.charAt(0).toUpperCase()}${string?.slice(1).toLowerCase()}`;
}
/**
* Generate documentation snippet for one route
* @typedef {import('../types.js').RouteMeta} RouteMeta
*
* @param routeMeta {RouteMeta} A route instance with its meta information
* @param schemaName {string} Path to directory that will contain relevant schemas for the route
* @param tagsToKeep {string[]} Tags / keywords that can be used for grouping routes
* @returns {import('openapi-types').OpenAPIV3.PathItemObject}
*/
export function generateOpenAPIForRoute({route, description, tags}, schemaName, tagsToKeep) {
/** @type {(name: string) => ({$ref: string})} */
const schema = name => ({$ref: `./${schemaName}#/definitions/${name}`});
/** @type {import('openapi-types').OpenAPIV3.ResponsesObject} */
const responses = Object.fromEntries(
route.instance.errorNames
.map(RouteError => new RouteError())
.map(error => [
error.statusCode,
{
description:
error.message ?? capitalize(error.name.replaceAll(/([A-Z][a-z])/g, ' $1').replace('SC ', '')),
content: {
'application/json': {
schema: schema(error.name),
},
},
},
]),
);
/** @type {import('openapi-types').OpenAPIV3.ParameterObject[]} */
const parameters = Object.entries(route.instance.obligatoryParameters ?? {}).map(
([parameter, schemaDefinition]) => ({
in: 'path',
name: parameter,
required: true,
schema: schema(schemaDefinition),
}),
);
/** @type {import('openapi-types').OpenAPIV3.OperationObject} */
const operation = {
summary: capitalize(description?.replace(/(Route to |Route for )/gim, '')),
requestBody: {
description: route.responseBodyDescription ?? undefined,
content: {
'application/json': {
schema: schema(route.instance.requestBodyName),
},
},
},
parameters: [
{
name: 'X-StApps-Version',
in: 'header',
schema: {
type: 'string',
example: '2.0.0',
},
required: true,
},
...parameters,
],
responses: {
200: {
description: route.responseBodyDescription,
content: {
'application/json': {
schema: schema(route.instance.responseBodyName),
},
},
},
...responses,
},
tags: tags?.filter(value => tagsToKeep.includes(value)),
};
return {[route.instance.method.toLowerCase()]: operation};
}