mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-11 12:12:55 +00:00
217 lines
6.8 KiB
TypeScript
217 lines
6.8 KiB
TypeScript
/*
|
|
* Copyright (C) 2018-2019 StApps
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
import {asyncPool} from '@krlwlfrt/async-pool';
|
|
import {Logger} from '@openstapps/logger';
|
|
import {basename, dirname, join} from 'path';
|
|
import {ProjectReflection} from 'typedoc';
|
|
import {Type} from 'typedoc/dist/lib/models';
|
|
import {NodesWithMetaInformation, NodeWithMetaInformation, RouteWithMetaInformation} from './common';
|
|
|
|
/**
|
|
* Gather relevant information of routes
|
|
*
|
|
* This gathers the information for all routes that implement the abstract class SCAbstractRoute.
|
|
* Furthermore it instantiates every route and adds it to the information.
|
|
*
|
|
* @param reflection Contents of the JSON representation which Typedoc generates
|
|
*/
|
|
export async function gatherRouteInformation(reflection: ProjectReflection): Promise<RouteWithMetaInformation[]> {
|
|
const routes: RouteWithMetaInformation[] = [];
|
|
|
|
if (!Array.isArray(reflection.children)) {
|
|
throw new Error('Project reflection doesn\'t contain any modules.');
|
|
}
|
|
|
|
// tslint:disable-next-line:no-magic-numbers
|
|
await asyncPool(2, reflection.children, async (module) => {
|
|
if (Array.isArray(module.children) && module.children.length > 0) {
|
|
// tslint:disable-next-line:no-magic-numbers
|
|
await asyncPool(2, module.children, (async (node) => {
|
|
if (Array.isArray(node.extendedTypes) && node.extendedTypes.length > 0) {
|
|
if (node.extendedTypes.some((extendedType) => {
|
|
// tslint:disable-next-line:completed-docs
|
|
return (extendedType as (Type & { name: string; })).name === 'SCAbstractRoute';
|
|
})) {
|
|
Logger.info(`Found ${node.name} in ${module.originalName}.`);
|
|
|
|
if (Array.isArray(module.originalName.match(/\.d\.ts$/))) {
|
|
module.originalName = join(dirname(module.originalName), basename(module.originalName, '.d.ts'));
|
|
Logger.info(`Using compiled version of module in ${module.originalName}.`);
|
|
}
|
|
|
|
const importedModule = await import(module.originalName);
|
|
|
|
const route = new importedModule[node.name]();
|
|
|
|
routes.push({description: node.comment!, name: node.name, route});
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
});
|
|
|
|
if (routes.length === 0) {
|
|
throw new Error('No route information found.');
|
|
}
|
|
|
|
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
|
|
*
|
|
* @param name Name of the node
|
|
* @param node Node itself
|
|
*/
|
|
export function getLinkForNode(name: string, node: NodeWithMetaInformation): string {
|
|
let link = 'https://openstapps.gitlab.io/core/';
|
|
const module = node.module
|
|
.toLowerCase()
|
|
.split('/')
|
|
.join('_');
|
|
|
|
if (node.type === 'Type alias') {
|
|
link += 'modules/';
|
|
link += `_${module}_`;
|
|
link += `.html#${name.toLowerCase()}`;
|
|
|
|
return link;
|
|
}
|
|
|
|
let type = 'classes';
|
|
if (node.type !== 'Class') {
|
|
type = `${node.type.toLowerCase()}s`;
|
|
}
|
|
|
|
link += `${type}/`;
|
|
link += `_${module}_`;
|
|
link += `.${name.toLowerCase()}.html`;
|
|
|
|
return link;
|
|
}
|
|
|
|
/**
|
|
* Generate documentation snippet for one route
|
|
*
|
|
* @param routeWithInfo A route instance with its meta information
|
|
* @param nodes Nodes with meta information
|
|
*/
|
|
export function generateDocumentationForRoute(routeWithInfo: RouteWithMetaInformation,
|
|
nodes: NodesWithMetaInformation): string {
|
|
let output = '';
|
|
|
|
const route = routeWithInfo.route;
|
|
|
|
output += `## \`${route.method} ${route.urlFragment}\``;
|
|
output += ` ${getLinkedNameForNode(routeWithInfo.name, nodes[routeWithInfo.name], true)}\n\n`;
|
|
|
|
if (typeof routeWithInfo.description.shortText === 'string') {
|
|
output += `**${routeWithInfo.description.shortText}**\n\n`;
|
|
}
|
|
|
|
if (typeof routeWithInfo.description.text === 'string') {
|
|
output += `${routeWithInfo.description.text.replace('\n', '<br>')}\n\n`;
|
|
}
|
|
|
|
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!,
|
|
};
|
|
});
|
|
}
|
|
});
|
|
|
|
return nodes;
|
|
}
|